草庐IT

关于 c#:Refresh 与绑定到其他属性的转换器的绑定

codeneng 2023-03-28 原文

Refresh binding with converter bound to other property

我目前正在为 Windows 10 构建一个 WinRT 应用程序,但我遇到了一个我似乎无法找到答案的问题。

在我的主页中,我的 ViewModel 中有一个绑定到 ObservableCollection 的地图标记列表。对于这些标记中的每一个,我需要根据我的 ViewModel 的另一个属性(我们称之为 PropertySelector)的值,从我的 MapMarker 类中显示一个可以是 Property1 或 Property2 的文本。

我找到的最佳解决方案是在 MapMarker 类中创建一个同时包含 Property1 和 Property2 的结构,将其绑定到标记的文本字段并使用转换器选择要显示的一个。

由于您无法将属性绑定到 ConverterParameter,因此我在 Converter 中实现了 DependencyProperty 以使其能够访问 PropertySelector。 DP 工作正常,转换器中的属性得到更新,但标记永远不会更新。我知道这是因为我没有触发任何实际告诉标记更新的事件,但是我没有通过将 PropertyChanged("MarkerList") 添加到 PropertySelector 设置器或尝试以编程方式刷新绑定来实现它当我用 GetBinding(Text).UpdateSource() 之类的东西更改属性时,顺便说一下,这似乎与 WPF 有不同的实现。

我这样做对吗?我能做些什么来强制绑定刷新?

这是我的相关代码:

MainPage.xaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<Page.Resources>
        <local:PropertySelectorConverter x:Key="propertySelectorConverter"
                                   PropertySelector="{Binding PropertySelector}" />
</Page.Resources>

...

<Maps:MapControl>
    <Maps:MapItemsControl ItemsSource="{Binding MarkerList}">
        <Maps:MapItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Properties, Converter={StaticResource propertySelectorConverter}}" />
            </DataTemplate>
        </Maps:MapItemsControl.ItemTemplate>
    </Maps:MapItemsControl>
</Maps:MapControl>
<Button Text="Switch Data" Click="SwitchButton_Click" />

MainPage.xaml.cs

1
2
3
4
public void SwitchButton_Click(object sender, EventArgs e)
{
    viewModel.PropertySelector= !viewModel.PropertySelector
}

ViewModel.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class ViewModel : INotifyPropertyChanged
{
    private ObservableCollection<Marker> markerList = new ObservableCollection<Marker>();
    public ObservableCollection<Marker> MarkerList
    {
        get { return markerList; }
        set { markerList = value; OnPropertyChanged("MarkerList"); }
    }

    private bool propertySelector = false;
    public bool PropertySelector
    {
        get { return propertySelector; }
        set { propertySelector = value; OnPropertyChanged("PropertySelector"); }
    }
}

Marker.cs

1
2
3
4
public class Marker
{
    public Tuple<double, double> Properties { get; set; } = Tuple.Create(10, 7);
}

转换器.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class PropertySelectorConverter : DependencyObject, IValueConverter
{
    public bool PropertySelector
    {
        get { return (bool)GetValue(PropertySelectorProperty); }
        set { SetValue(PropertySelectorProperty, value); }
    }

    public static readonly DependencyProperty PropertySelectorProperty =
        DependencyProperty.Register("PropertySelector", typeof(bool), typeof(PropertySelectorConverter), new PropertyMetadata(null, CurrentItemChangedCallback));

    private static void CurrentItemChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {

    }

    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var properties = (Tuple<double, double>)value;
        return PropertySelector ? properties.Item1 : properties.Item2;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

感谢您的宝贵时间。


缺少一个好的、最小的、完整的代码示例来清楚地说明您的问题,即使不是不可能,也很难提供具体的建议。但是有一些一般的想法要分享……

首先,根据我的经验,ConverterParameter 对于提供给转换器的静态(即编译时)信息更有用。例如。当您编写了一个通用转换器时,该转换器需要一些特定数据用于给定绑定,但该数据值在编译时是已知的。

在您的场景中,您实际上有多个在运行时变化的转换器输入值。对于这种情况,恕我直言,使用 MultiBinding 更合适。这允许您提供两个或多个绑定源,如果其中任何一个源发生更改,WPF 将重新计算绑定值。不幸的是,这是一项 WPF 功能,并且与许多非常有用的 WPF 功能一样,已从 Windows Store/Winrt API 中省略。

但是,您可以构建一个简单的中间视图模型类来完成相同的任务。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class MultiBindingViewModel : DependencyObject
{
    public static readonly DependencyProperty PropertiesProperty = DependencyProperty.Register(
       "Properties", typeof(Tuple<double, double>), typeof(MultiBindingViewModel), new PropertyMetadata(null, OnPropertyChanged);
    public static readonly DependencyProperty PropertySelectorProperty = DependencyProperty.Register(
       "PropertySelector", typeof(bool), typeof(MultiBindingViewModel), new PropertyMetadata(null, OnPropertyChanged);
    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
       "Value", typeof(double), typeof(MultiBindingViewModel), null);

    public Tuple<double, double> Properties
    {
        get { return (Tuple<double, double>)GetValue(PropertiesProperty); }
        set { SetValue(PropertiesProperty, value); }
    }

    public bool PropertySelector
    {
        get { return (bool)GetValue(PropertySelectorProperty); }
        set { SetValue(PropertySelectorProperty, value); }
    }

    public double Value
    {
        get { return (double)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MultiBindingViewModel model = (MultiBindingViewModel)d;

        model.Value = model.PropertySelector ? model.Properties.Item1 : model.Properties.Item2;
    }
}

然后在您的 XAML 中使用它,例如:

1
2
3
4
5
6
7
8
9
10
<TextBlock>
    <TextBlock.Text>
        <Binding Path="Value">
            <Binding.Source>
                <local:MultiBindingViewModel Properties="{Binding Properties}"
                                             PropertySelector="{Binding PropertySelector}/>
            </Binding.Source>
        </Binding>
    </TextBlock.Text>
</TextBlock>

警告:缺少完整的代码示例,以上只是浏览器编写的代码。可能存在语法错误,或者我什至可能遗漏了一些 Windows 应用商店所需的关键代码。当然,确切的绑定源、路径和 XML 命名空间可能需要一些调整,因为我无法确定您是如何设置数据上下文等的。

但希望以上内容清楚地显示了您可以在项目中使用它的基本方法。

为了完整起见,以下是使用 MultiBinding 的 WPF 方法的样子:

MultiBinding 将始终有一个转换器,实现 IMultiValueConverter。该接口的 Convert() 方法看起来与 IValueConverter 的方法相似,不同之处在于它没有允许转换单个输入值的 object value 参数,而是具有 object[] values 参数。

根据您提供的代码,我希望您的转换器如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class PropertySelectorConverter : IMultiValueConverter
{    
    public object Convert(object[] values, Type targetType, object parameter, string language)
    {
        var properties = (Tuple<double, double>)values[0];
        bool propertySelector = (bool)values[1];

        return propertySelector ? properties.Item1 : properties.Item2;
    }

    public object ConvertBack(object[] values, Type targetType, object parameter, string language)
    {
        throw new NotSupportedException();
    }
}

然后在你的 XAML 中,你会做这样的事情:

1
2
3
4
5
6
7
8
<TextBlock>
    <TextBlock.Text>
        <MultiBinding Converter="{StaticResource propertySelectorConverter}">
            <Binding Source="." Path="Properties"/>
            <Binding Source="." Path="PropertySelector"/>
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

  • 我知道 MultiBinding 及其在 WinRT 中的缺失,但我认为我无法重新创建它。我会继续尝试实现这一点,它看起来很有希望。非常感谢您的宝贵时间 !
  • 效果很好,但您需要将 MultiBindingViewModel 放在 DataTemplate 资源中,而不是直接放在 Text 绑定中。
  • @JabX 您介意解释一下您对数据模板资源的含义吗? afaik 数据模板没有资源属性,如果直接在属性绑定中写入,它确实不起作用。
  • 好的,它使用了数据模板的第一个孩子的资源。但是,现在当其中一个绑定更改时,它不会更新。
  • @Stefan:感谢您纠正我的错字。至于您的具体问题,听起来您应该发布一个新问题,如果您仍然无法使代码正常工作。确保您包含一个良好的、最小的、完整的代码示例,可以可靠地重现问题。此外,请具体说明正在发生的事情(例如,"绑定更改"可能意味着绑定属性的值,或者实际用于绑定的不同属性)。
  • @PeterDuniho 是的,我知道。我已经解决了。它不喜欢绑定到其他元素的属性(数据模板资源之外)。由于我需要的属性无论如何都是静态的,因此我在 ViewModel 类中对绑定进行了建模。

有关关于 c#:Refresh 与绑定到其他属性的转换器的绑定的更多相关文章

  1. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  2. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  3. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  4. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  5. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  6. ruby - 将散列转换为嵌套散列 - 2

    这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[

  7. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  8. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  9. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  10. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

随机推荐