我正在尝试绑定窗口标题属性,以便它显示对象的文件名和修改状态.文件名和修改后的状态都是对象的依赖属性.
我知道我可能只是在对象中添加一个“WindowTitle”属性,但这看起来相当hacky.我已经创建了一个非常精简的版本,我正在尝试做的事情.
这是XAML:
<Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="{Binding Converter={StaticResource windowTitleConverter}}" Height="195" Width="245"> <Window.Resources> <local:WindowTitleConverter x:Key="windowTitleConverter"/> </Window.Resources> <Grid Height="150" Width="217"> <TextBox Height="23" HorizontalAlignment="Left" Margin="12,12,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding FileName}" /> <CheckBox Content="Modified" Height="16" HorizontalAlignment="Left" Margin="12,41,0" Name="checkBox1" VerticalAlignment="Top" IsChecked="{Binding Modified}" /> </Grid>
和守则:
using System; using System.Globalization; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; namespace WpfApplication1 { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new Foo(); } } public class Foo : DependencyObject { public string FileName { get { return (string)GetValue(FileNameProperty); } set { SetValue(FileNameProperty,value); } } public static readonly DependencyProperty FileNameProperty = DependencyProperty.Register("FileName",typeof(string),typeof(Foo),new UIPropertyMetadata()); public bool Modified { get { return (bool)GetValue(ModifiedProperty); } set { SetValue(ModifiedProperty,value); } } public static readonly DependencyProperty ModifiedProperty = DependencyProperty.Register("Modified",typeof(bool),new UIPropertyMetadata(0)); } public class WindowTitleConverter : IValueConverter { public object Convert(object value,Type targetType,object parameter,CultureInfo culture) { Foo foo = (Foo)value; if (foo == null || foo.FileName == null) return "Foo"; return foo.FileName + (foo.Modified ? " *" : ""); } public object ConvertBack(object value,CultureInfo culture) { throw new NotSupportedException(); } } }
解决方法
如果你移动资源下面的标题绑定它将工作.我不确定为什么声明的顺序在这里很重要,但它似乎对我来说是个错误
<Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Height="195" Width="245"> <Window.Resources> <local:WindowTitleConverter x:Key="windowTitleConverter"/> </Window.Resources> <Window.Title> <Binding Converter="{StaticResource windowTitleConverter}"/> </Window.Title> <!--...--> </Window>
更新
您现在遇到的问题是因为Dependency Property Modified具有错误的默认值类型.它是bool类型,你将它设置为0,所以将其更改为false,它应该工作
public static readonly DependencyProperty ModifiedProperty = DependencyProperty.Register("Modified",new UIPropertyMetadata(false));
更新
在直接绑定到DataContext时,我不知道有任何方法可以引发PropertyChanged.您可以使用的一个小解决方法是绑定到一个名为This的属性,它只返回它
<Window.Title> <Binding Path="This" Converter="{StaticResource windowTitleConverter}"/> </Window.Title>
然后,您可以使用PropertyChangedCallback为此引发PropertyChanged
public class Foo : DependencyObject,INotifyPropertyChanged { public Object This { get { return this; } } public bool Modified { get { return (bool)GetValue(ModifiedProperty); } set { SetValue(ModifiedProperty,value); } } public string FileName { get { return (string)GetValue(FileNameProperty); } set { SetValue(FileNameProperty,value); } } public static readonly DependencyProperty FileNameProperty = DependencyProperty.Register("FileName",new UIPropertyMetadata(string.Empty,new PropertyChangedCallback(OnFileNameChanged))); public static readonly DependencyProperty ModifiedProperty = DependencyProperty.Register("Modified",new UIPropertyMetadata(false,new PropertyChangedCallback(OnModifiedChanged))); private static void OnFileNameChanged(DependencyObject obj,DependencyPropertyChangedEventArgs e) { Foo foo = obj as Foo; foo.OnPropertyChanged("This"); } private static void OnModifiedChanged(DependencyObject obj,DependencyPropertyChangedEventArgs e) { Foo foo = obj as Foo; foo.OnPropertyChanged("This"); } public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this,new PropertyChangedEventArgs(propertyName)); } } }
另一种解决方案是使用MultiBinding,这样就不需要使用This属性了
<Window.Resources> <local:TitleMultiConverter x:Key="TitleMultiConverter"/> </Window.Resources> <Window.Title> <MultiBinding Converter="{StaticResource TitleMultiConverter}"> <Binding Path="FileName"/> <Binding Path="Modified"/> </MultiBinding> </Window.Title>
TitleMultiConverter
public class TitleMultiConverter : IMultiValueConverter { public object Convert(object[] values,CultureInfo culture) { string fileName = values[0].ToString(); bool modified = (bool)values[1]; if (fileName == null) return "Foo"; return fileName + (modified ? " *" : ""); } public object[] ConvertBack(object value,Type[] targetTypes,CultureInfo culture) { throw new NotImplementedException(); } }