c# - 使用转换器将窗口标题绑定(bind)到属性

标签 c# wpf data-binding

我正在尝试绑定(bind)窗口 Title 属性,以便它显示对象的文件名和修改状态。文件名和修改状态都是对象的依赖属性。

我知道我可能只向对象添加一个“WindowTitle”属性或类似属性,但这看起来很老套。我已经创建了一个我正在尝试做的非常精简的版本。

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

代码:

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();
        }
    }
}

最佳答案

如果您将 Title 绑定(bind)移动到资源下方,它将起作用。我不确定为什么声明的顺序在这里很重要,但它对我来说似乎是一个错误

<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",
                                typeof(bool),
                                typeof(Foo),
                                new UIPropertyMetadata(false));

更新

我不知道有什么方法可以在直接绑定(bind)到 DataContext 时引发 PropertyChanged。您可以使用的一个小解决方法是绑定(bind)到一个名为 This 的属性,它只返回 this

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

然后您可以使用 PropertyChangedCallback 为 This 引发 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",
                                    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));
        }
    }
}

另一种解决方案是使用 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, 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();
    }
}

关于c# - 使用转换器将窗口标题绑定(bind)到属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5422635/

相关文章:

c# - 单独的辅助角色与 Windows 服务以及另一个角色

c# - 如何使用 azure.security.keyvault 中的新 keyvault 客户端进行签名

c# - NHibernate 是否应该清除 ISessionFactory.Dispose 上的分布式二级缓存?

c# - 在 WPF 中的动画之前设置手动控件属性不起作用

c# - 防止无效的文本框输入绑定(bind)到业务对象属性?

C#:尝试在不同类中使用控制元素 - "object reference is required"

wpf - 如何创建圆形 slider WPF

c# - 为什么RenderTransformOrigin的center是0.5,0.5?

.net - 如何在值不等于的情况下使用数据触发器

java - 如何在 CQL 3 准备语句中绑定(bind) IN 子句值?