c# WPF绑定自定义属性
本文关键字:自定义属性 绑定 WPF | 更新日期: 2023-09-27 17:54:25
我有一个c# WPF MVC应用程序。我的目标是为我所有的窗口创建一个标题栏。
我创建了这个:
XAML:<Grid x:Class="Views.TitleBarView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Views"
mc:Ignorable="d"
Style="{DynamicResource TitleStyleGrid}"
x:Name="barView">
<Label x:Name="labelAppName" Style="{DynamicResource TitleStyleLabel}" Content="{Binding Content, ElementName=barView}"/>
<Button x:Name="bttnClose" Style="{DynamicResource ButtonStyleCloseWindow}" Command="{Binding CloseCommand}"/>
</Grid>
c#: public partial class TitleBarView : Grid
{
static TitleBarView()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TitleBarView), new FrameworkPropertyMetadata(typeof(TitleBarView)));
}
public readonly static DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(string), typeof(TitleBarView), new PropertyMetadata(""));
public string Content
{
get { return (string)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public TitleBarView()
{
InitializeComponent();
TitleBarViewModel tvm = new TitleBarViewModel();
tvm.RequestClose += (s, e) => this.Close();
DataContext = tvm;
}
private void Close()
{
Window.GetWindow(this).Close();
}
}
我已经为我的Grid
创建了属性Content
,并且label
内部绑定了这个属性。所以当我调用我的类TitleBarView
时,我只需要设置属性"Content"和标签自动更新。
当我直接用String:
设置内容时效果很好<Window [...]
xmlns:local="clr-namespace:VectorReaderV3.Views"
[...]>
<local:TitleBarView x:Name="titleBar" Content="My Title"/>
<Window/>
但是对于binding,我有一个空标题:
<Window [...]
xmlns:local="clr-namespace:VectorReaderV3.Views"
[...]>
<local:TitleBarView x:Name="titleBar" Content="{Binding WindowTitle}">
<Window/>
我做错了什么?
在您的代码中,您将TitleBarView的数据上下文设置为后面代码中创建的TitleBarViewModel。这意味着"WindowTitle"属性必须在TitleBarViewModel上(我猜它不是?)。
你不能像从UserControl继承标准控件那样创建自定义控件。原因是在创建自定义控件时,您希望用户创建视图模型并提供数据上下文,因此您不能在后面的代码中创建它。
这涉及到更多的工作,但它归结为:
- 样式定义了控件的外观,它必须位于ResourceDictionary中,它在Themes/Generic中定义/包含。Xaml文件(是的,特定的位置)。样式必须有一个与代码隐藏文件名称匹配的TargetType。
- 文件后面的代码继承自一个UI类(在你的例子中是Grid),并覆盖了上面的默认样式-正如你所做的。
- 样式可以使用特定的TemplateBinding绑定到文件后面代码的属性。
- 如果后面的代码需要访问样式中的命名元素,它必须使用GetTemplateChild("NameOfElement")来查找它们-这通常在ApplyTemplate的重写中完成,例如hook up button事件句柄。
这里有一个更详细的教程:http://www.wpftutorial.net/howtocreateacustomcontrol.html
如果你想修改现有的控件,同样的过程也适用。
将Content="{Binding Content, ElementName=barView}"
更改为Content="{Binding Content, RelativeSource={RelativeSource AncestorType=local:TitleBarView}}}"
并告诉发生了什么
我已经修改了使用我的TitleBarView
的ViewModel:
public class MessageBoxViewModel : ViewModelBase
{
protected String windowTitle;
public String WindowTitle {
get { return windowTitle; }
set { windowTitle = value; OnPropertyChanged("WindowTitle"); } }
}
和关联的View:
c#:public partial class MessageBoxView : Window
{
private MessageBoxView()
{
InitializeComponent();
MessageBoxViewModel dvm = new MessageBoxViewModel();
dvm.PropertyChanged += (s, e) => this.PropertyChanged(s,e);
DataContext = dvm;
}
private void PropertyChanged(object e, PropertyChangedEventArgs s)
{
if (s.PropertyName == "WindowTitle")
{
titleBar.Content = (DataContext as MessageBoxViewModel).WindowTitle;
}
}
}
XAML: <Window Title="MessageBoxView"
Style="{DynamicResource WindowStyle}">
<local:TitleBarView x:Name="titleBar" Content="{Binding WindowTitle}"/>
/>
它工作,但我不确定它尊重模式MVC。这是我的第一个MVC应用程序,我很困惑。