Binding window title to properties using converter

I am trying to bind the Title attribute of a window so that it displays the file name and the changed status for the object. The file name and changed state are both object dependency properties.

I know that I could just add a WindowTitle or such property to the object, but that seems pretty hacky. I created a very stripped down version of what I'm trying to do.

Here is the 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,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding FileName}" /> <CheckBox Content="Modified" Height="16" HorizontalAlignment="Left" Margin="12,41,0,0" Name="checkBox1" VerticalAlignment="Top" IsChecked="{Binding Modified}" /> </Grid> 

And the code:

 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), typeof(Foo), 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, Type targetType, object parameter, CultureInfo culture) { throw new NotSupportedException(); } } } 
+4
source share
1 answer

If you move the Title binding below Resources, it will work. I'm not sure why the order of the ads matters here, but this seems to be a mistake for me

 <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> 

Update

The problem you are currently facing is that the modified dependency property has the wrong default value type. This is a bool type, and you set it to 0 to change it to false, and it should work

 public static readonly DependencyProperty ModifiedProperty = DependencyProperty.Register("Modified", typeof(bool), typeof(Foo), new UIPropertyMetadata(false)); 

Update

I don't know how to enhance PropertyChanged when binding directly to a DataContext. A small workaround you can use is to bind to the "This" property, which simply returns this

 <Window.Title> <Binding Path="This" Converter="{StaticResource windowTitleConverter}"/> </Window.Title> 

Then you can use PropertyChangedCallback to raise PropertyChanged for this

 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", typeof(string), typeof(Foo), new UIPropertyMetadata(string.Empty, new PropertyChangedCallback(OnFileNameChanged))); public static readonly DependencyProperty ModifiedProperty = DependencyProperty.Register("Modified", typeof(bool), typeof(Foo), 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)); } } } 

Another solution would be to use MultiBinding instead, which will eliminate the need for this property.

 <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, Type targetType, object parameter, 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, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } 
+10
source

Source: https://habr.com/ru/post/1345126/


All Articles