【问题标题】:WPF Force rebindWPF 强制重新绑定
【发布时间】:2009-06-05 18:58:16
【问题描述】:

我有一个不能继承 DependencyObject 或使用 NotifyPropertyChanged 的​​对象,并且我已经将它绑定到很多控件,所以当属性更改时,我不想去每个控件并更改它的值代码,所以我认为必须有一种方法可以告诉 XAML 用一两行代码“重新绑定”它所绑定的所有内容,而不是去:

label1.Content = myObject.DontNotifyThis;
label2.Content = myObject.DontNotifyThisEither;
label3.Content = myObject.DontEvenThinkOfNotifyingThis;
label4.Content = myObject.NotSoFastPal;

等等,等等……

这是一个过于简单的例子:

XAML:

<Window x:Class="StackOverflowTests.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" x:Name="window1" Height="300" Width="300" Loaded="window1_Loaded">
    <Grid x:Name="gridMain">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Label Grid.Row="0" Content="{Binding Status}" ContentStringFormat="Today's weather: {0}" />
        <Label Grid.Row="2" Content="{Binding Temperature}" ContentStringFormat="Today's temperature: {0}" />
        <Label Grid.Row="1" Content="{Binding Humidity}" ContentStringFormat="Today's humidity: {0}" />
    </Grid>
</Window>

C#:

using System.Windows;

namespace StackOverflowTests
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        Weather weather = new Weather("Cloudy", "60F", "25%");

        public Window1()
        {
            InitializeComponent();
            this.DataContext = weather;
        }

        private void window1_Loaded(object sender, RoutedEventArgs e)
        {
            weather.Status = "Sunny";
            weather.Temperature = "80F";
            weather.Humidity = "3%";
        }       
    }

    class Weather
    {
        public string Status { get; set; }
        public string Temperature { get; set; }
        public string Humidity { get; set; }

        public Weather(string status, string temperature, string humidity)
        {
            this.Status = status;
            this.Temperature = temperature;
            this.Humidity = humidity;
        }
    }
}

我找到了一种方法,但它一点也不优雅,而且不幸的是,我不能只将 DataContext 设置为一个新的天气实例,它需要是相同的引用(这就是为什么我将它设置为null 所以它会改变):

private void window1_Loaded(object sender, RoutedEventArgs e)
{
    weather.Status = "Sunny";
    weather.Temperature = "80F";
    weather.Humidity = "3%";

    // bad way to do it
    Weather w = (Weather)this.DataContext;
    this.DataContext = null;
    this.DataContext = w;
}   

提前致谢!

【问题讨论】:

  • 好奇:为什么不能实现 INPC?
  • 我们在我们的应用程序上使用撤消/重做,INotifyPropertyChanging 序列化对象的先前状态,INotifyPropertyChanged 允许将对象保存到新的 XmlSerialized 文件中。但是,我需要更改的这些特定属性不会更改对象的保存状态(不会更改字体、颜色、背景、边框)或用户想要保存的任何内容。如果我 NotifyPropertyChanging / Changed 使用这些属性,系统会认为对象已更改,但对用户而言,事实并非如此。这就是我不能使用它的原因。
  • 明白,但这对我来说听起来像是一个有缺陷的设计。您最好使用 INPC 作为通用属性更改通知,然后使用另一种机制来跟踪您关心的撤消/重做的状态更改。不过,更改您的设计可能为时已晚,所以请指出。
  • 另外需要注意的是,MSDN 的创建依赖属性的例子是不完整的。感谢这篇博文,我得救了:geekswithblogs.net/thibbard/archive/2008/04/22/…
  • 为什么方法不好?我喜欢它。它省去了将所有属性重写为 dp 的麻烦,并使我的代码保持简单。我只需要在我的对话框中添加一个重置按钮来恢复我所有控件的默认值,这真的让我很开心。

标签: wpf binding


【解决方案1】:

如果您有权访问要更新绑定的元素,则可以显式更新绑定。您可以检索元素上的绑定表达式,然后使用 UpdateTarget() 刷新 UI,或使用 UpdateSource 刷新支持属性(如果您想绑定到诸如 TextBox 之类的可编辑内容)。

这里有一个简单的例子来演示它:

<StackPanel>
    <TextBlock x:Name="uiTextBlock" Text="{Binding MyString}" />
    <Button Click="Button_Click"
            Content="Rebind" />
</StackPanel>

public partial class Window1 : Window
{
    public string MyString { get; set; }

    public Window1()
    {
        MyString = "New Value";

        InitializeComponent();
        this.DataContext = this;
    }
    int count = 0;
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        MyString = "Rebound " + ++count + " times";

        var bindingExpression = uiTextBlock.GetBindingExpression(TextBlock.TextProperty);
        bindingExpression.UpdateTarget();
    }
}

(如果可能的话,我建议使用 INotifyPropertyChanged。这样你就可以从后面的代码中提取逻辑。)

【讨论】:

  • 好吧,这行得通,唯一的问题是,我必须为需要更新的每个控件都这样做吗?
  • 如果你不能实现 INotifyPropertyChanged,那么可以。您可以创建所需的 BindingExpressions 集合,然后使用 linq 扩展名 .ForEach(b => b.UpdateTarget())。如果您必须更新很多东西,或者一次只能访问一些控件,那么像您已经找到的那样“循环”DataContext 可能会更简单。
  • 我认为更新每个控件都是可行的,我唯一不喜欢这种方法的是,如果我添加一个新控件,我将不得不在代码中添加它来更新它目标也。但没什么大不了的。谢谢!
【解决方案2】:

当你想更新一堆绑定表达式时,这是非常难看的。更好的方法是卷影复制:

public partial class MainWindow : Window
{
    Weather weather = new Weather("Cloudy", "60F", "25%");
    public MainWindow()
    {
        InitializeComponent();

        
        this.DataContext = weather;
        this.Loaded += delegate
        {
            weather.Status = "Sunny";
            weather.Temperature = "80F";
            weather.Humidity = "3%";

            
            this.DataContext = weather.ShadowCopy();
        };
    }
    
    class Weather
    {
        public string Status { get; set; }
        public string Temperature { get; set; }
        public string Humidity { get; set; }

        public Weather(string status, string temperature, string humidity)
        {
            this.Status = status;
            this.Temperature = temperature;
            this.Humidity = humidity;
        }

        public Weather ShadowCopy() => this.MemberwiseClone() as Weather;
    }
}

第二种方法是使用包装器,例如:

    <Label Grid.Row="0" Content="{Binding Weather.Status}" ContentStringFormat="Today's weather: {0}" />
    <Label Grid.Row="2" Content="{Binding Weather.Temperature}" ContentStringFormat="Today's temperature: {0}" />
    <Label Grid.Row="1" Content="{Binding Weather.Humidity}" ContentStringFormat="Today's humidity: {0}" />

    public MainWindow()
    {
        InitializeComponent();


        this.DataContext = new DataSource { Weather = weather };
        this.Loaded += delegate
        {
            weather.Status = "Sunny";
            weather.Temperature = "80F";
            weather.Humidity = "3%";


            this.DataContext = new DataSource { Weather = weather };
        };
    }


    class DataSource
    {
        public Weather Weather { get; set; }
    }

【讨论】:

    猜你喜欢
    • 2011-08-06
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-05
    • 2013-05-09
    • 1970-01-01
    • 2017-03-22
    • 2018-06-09
    相关资源
    最近更新 更多