附加属性的怀疑

时间:2015-06-03 03:05:39

标签: c# wpf xaml

嗯,标题不是很具描述性,因为它们不知道如何命名我正在寻找的东西。我会尽力解释它。

在.xaml文件中,一个控件(假设一个文本框),如果键入" Text",则不能再次使用该属性。如果我们手动编写,编译器会显示错误。好已经解释了为什么我认为它现在更容易。

现在假设我有两个(DependencyProperty.RegisterAttached ......),名称为" Propiedad_1"和" Propiedad_2"是可能的,如果我已经使用过一个,那么另一个不能在同一个控件中使用,反之亦然?

2)另一个问题,在string类型的依赖属性中,是否可以检查String是否在某些时候发生了变化(试图不使用变量然后进行比较),我需要避免花费TexBox并避免textbox.TextChanged事件。

谢谢!

修改

这就是我现在所拥有的。

public static readonly DependencyProperty FilterSourceProperty =
    DependencyProperty.RegisterAttached("FilterSource", typeof (TextBox), typeof (ListViewExtension),
        new FrameworkPropertyMetadata(null, OnTextBoxTextChanged));

public static TextBox GetFilterSource(DependencyObject dObj)
{
    return (TextBox) dObj.GetValue(FilterSourceProperty);
}

public static void SetFilterSource(DependencyObject dObj, TextBox value)
{
    dObj.SetValue(FilterSourceProperty, value);
}

private static void OnTextBoxTextChanged(DependencyObject dObj, DependencyPropertyChangedEventArgs e)
{
    var listView = dObj as ListView;
    var textBox = e.NewValue as TextBox;

    if ((listView == null) || (textBox == null)) return;

    textBox.TextChanged += delegate(object sender, TextChangedEventArgs tcea)
    {

        var view = CollectionViewSource.GetDefaultView(listView.ItemsSource);
        if (view == null) return;
        view.Filter += item =>
        {
            ...
            ...
            ...
            ...
        };
    };
}

在.XAML

    <TextBox Name="TxtFilter"
             VerticalAlignment="Center"
             VerticalContentAlignment="Center"
             Text="{Binding Filter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" CharacterCasing="Upper"/>

<ListView Margin="0,5,0,0"
          ItemsSource="{Binding Articles}"
          IsSynchronizedWithCurrentItem="True"
          SelectedItem="{Binding SelectedArticle}"
          tools:ListViewExtension.FilterSource="{Binding ElementName=TxtFilter}">

在ViewModel中

public string Filter
{
    get { return _filter; }
    set
    {
        if (_filter == value) return;

        _filter = value;
        RaisePropertyChanged();
    }
}

我现在需要的是改变&#34; TextBox&#34;的使用。用一根绳子。

tools:ListViewExtension.FilterSource="{Binding Filter}"

1 个答案:

答案 0 :(得分:3)

由于缺乏a good, minimal, complete code example以及英语不佳,您的问题很难理解。后者是可以理解的(虽然你必须尽你所能确保你尽可能地进行沟通),但前者肯定应该得到解决。

缺乏这些改进,我猜你的问题(两者......以备将来参考,请不要在同一篇文章中发表两个不同的问题)相当于以下内容:

  
      
  1. 我有两个附加属性,我想在XAML编辑器中互斥。这可能吗?
  2.   

没有。您所看到的行为仅适用于单个属性。如果您尝试多次设置相同的属性,编辑器会抱怨。但它很容易做到这一点,因为它所要做的就是检查元素中是否已经使用了该属性。

对于两个应该互斥的不同属性,没有任何可行的方法来修改编辑器或编译器的行为来检查它。

作为替代方案,考虑将两个互斥的值实现为单个属性,其中该属性可以接受给定类型的两个不同的子类,并且这些子类各自表示两个互斥属性类型中的一个。

  
      
  1. 我可以优化属性更新,这样如果分配的新值实际上与当前值相同,则不会更改&#34;属性#34;事件被提出?
  2.   

这是否可行取决于您的代码实际编写方式。在WPF中,通过使用DependencyPropertyINotifyPropertyChanged来支持绑定。这些都不会暗示TextChanged属性的对象中存在Text事件,您声明的事件是您不想提出的事件。

请注意,一般情况下,如果有效值(强制后)实际没有更改,DependencyObject.SetValue()将取消更改通知。另请注意,在大多数其他情况下,额外的更改通知通常不会成为真正的性能问题。

缺乏一个好的代码示例,可以提供关于第二个问题的更多建议。

如果您觉得这些答案没有合理或有用地解决您的问题,请改进您的帖子,以便更容易理解。


修改

关于第一个问题,并且根据您提供的代码段(不完整),我会说最简单的方法是让FilterSource具有object类型而不是TextBox,然后在OnTextBoxTextChanged()中,检查新值的类型并适当处理。即如果它是TextBox,请执行您现在正在做的事情(主要是...请参阅下面的(*)),如果它是string例如,只需直接配置视图的过滤器,而不是将配置放入事件处理程序。


(*)注意:

我发现OnTextBoxTextChanged()方法至少有两个方面的改进:

  1. 不需要仅因为文本更改而重建Filter事件处理程序。相反,您只需在视图上调用Refresh()即可。因此,在该方法中,您将为Filter事件实现事件处理程序,以始终检索用于过滤的TextBox.Text属性值。您将订阅该事件一次,然后TextChanged的事件处理程序将只调用Refresh()

    string方案中,您使用的Filter事件处理程序仅使用string值进行过滤,而无需处理(当然不存在){ {1}}事件。

  2. 更大的问题是您只订阅了TextChanged事件。如果您只更改TextChanged属性一次,那么您永远不会发现问题,但 是一个问题。如果再次更改属性值,则应在订阅新事件之前取消订阅旧事件处理程序。如果你进行了我上面描述的更改,FilterSource事件处理程序只调用TextChanged,那么这个bug的影响将会大大减少。但它仍然是一个错误。

  3. 结束注释。


    至于问题的第二部分,我没有看到需要解决的问题。不清楚您是否关注Refresh()属性或TextBox.Text属性,但我认为如果新设置的属性值相同,则两个属性都不会生成更改通知如旧。

    如果您有不同的想法,请提供更好的代码示例(最小完整),以清楚地说明实际问题发生的原因,清楚,准确地解释了问题是什么:代码目前的行为方式,以及与您希望的方式有何不同。


    考虑到以上所有因素,我认为您的FilterSource方法应该更像这样:

    OnTextBoxTextChanged()

    为了实现这一目标,您当然必须将附加财产的类型从private static void OnTextBoxTextChanged(DependencyObject dObj, DependencyPropertyChangedEventArgs e) { ListView listView = dObj as ListView; if (listView == null) return; var view = CollectionViewSource.GetDefaultView(listView.ItemsSource); if (view == null) return; if (e.NewValue is TextBox) { TextBox newValue = (TextBox)e.NewValue; view.Filter += item => { string filterString = newValue.Text; // filter based on filterString, etc. }; textBox.TextChanged += delegate(object sender, TextChangedEventArgs tcea) { view.Refresh(); }; } else if (e.NewValue is string) { string filterString = (string)e.NewValue; view.Filter += item => { // filter based on filterString, etc. }; } else return; } 更改为TextBox

    在上文中,我没有费心去解决objectTextChanged事件取消订阅的问题。如果您希望解决该特定问题,则相对简单:您需要取消订阅事件中的旧处理程序(对于Filter,仅当TextChanged当然为真时)。

    当然,要做到这一点,您需要在每个e.OldValue is TextBox对象的基础上存储旧的事件处理程序委托实例,例如:在字典中或者甚至只是拥有私有附加属性(类似于ListView属性,但对其他代码不可见)。这样,您可以稍后检索委托实例,以取消订阅事件。