可以将数据绑定到扩展方法吗? [英] Is it possible to databind to an extension method?

查看:135
本文介绍了可以将数据绑定到扩展方法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于这个问题的缺乏问题可能表明了这里的代码气味,但...可以为类和数据绑定编写一个类似于属性的扩展方法?



假设我被提供了一个类结构,我不能从根本上改变,但是我想将一系列布尔属性表达为一个用于显示目的的字符串。 p>

简化基类:

  public class Transmission 
{
public int ID {get;组; }
public bool取消{get;组; }
public bool存储{get;组; }
public bool Recorded {get;组;
}

我的扩展方法:

  public static class Extensions 
{
public static string Status(this Transmission trans)
{
StringBuilder sb = new StringBuilder |);
if(trans.Cancelled)
sb.Append(| Cancelled);
if(trans.Recorded)
sb.Append(| Recorded);
if(trans.Stored)
sb.Append(| Stored);
sb.Append(||);

return sb.ToString();
}
}

为了增加更多的复杂性,我被传递这些东西的列表,我试图绑定到一个datagrid(严重限制XAML的经验)。

 < GroupBox Header =这是一个惊人的结果列表,您可以非常可怕地违反。> 
< DataGrid ItemsSource ={Binding Transmissions,Mode = OneWay}AutoGenerateColumns =False>
< DataGrid.Columns>
< DataGridTextColumn Width =*Header =Local IDBinding ={Binding ID,Mode = OneWay}/>
< DataGridTextColumn Width =*Header =StatusBinding ={Binding Status,Mode = OneWay}/>
< /DataGrid.Columns>
< / DataGrid>
< / GroupBox>

我已经测试了代码,能够绑定到ID,没有任何困难。然而,状态根本没有被拾起。绑定到扩展属性有一个窍门吗?或者,只是写一个装饰器/门面类并绑定到这个更谨慎?

解决方案

当你通过列表的传输对象,您可以使用外观图案并将其存储在设计的容器中。

  public class TransmissionContainer:INotifyPropertyChanged 
{
私有readonly传输_传输;
public TransmissionContainer(传输传输)
{
_transmission =传输;
}
private int _id;
public int Id
{
[DebuggerStepThrough]
get {return _transmission.ID;
[DebuggerStepThrough]
set
{
if(value!= _transmission.ID)
{
_transmission.ID = value;
OnPropertyChanged(Id);
}
}
}
public bool取消
{
[DebuggerStepThrough]
get {return _transmission.Cancelled}
[ DebuggerStepThrough]
set
{
if(value!= _transmission.Cancelled)
{
_transmission.Cancelled = value;
OnPropertyChanged(已取消);
OnPropertyChanged(Status);
}
}
}
public string Status
{
[DebuggerStepThrough]
get
{
StringBuilder sb = new StringBuilder(|);
if(_transmission.Cancelled)
sb.Append(| Cancelled);
if(_transmission.Recorded)
sb.Append(| Recorded);
if(_transmission.Stored)
sb.Append(| Stored);
sb.Append(||);
return sb.ToString();
}
}
//
//其他属性中的代码
//
#region INotifyPropertyChanged实现
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged,null,null);
if(handler!= null)
{
handler(this,new PropertyChangedEventArgs(name));
}
}
#endregion
}

这是一个创建外观的容器类,您的Xaml可以透明地粘贴到该外观上。如图所示,每个暴露的属性都简单地回传了传输的私有实例中的值。更改通过INotifyPropertyChanged接口转发到WPF绑定引擎。



要创建一个实例,您可以使用原始的Transmission类来构造它。要绑定这些容器的集合,可以声明一个ObservableCollection类型为TransmissionContainer。这样做意味着除了属性的各种更改之外,列表也被绑定。



在这种方法中,你的'extension'属性只是另一个没有setter的暴露属性。请注意,影响状态的其他成员的更改将代表extension属性调用通知。传输类的剩余成员编码大约需要20分钟...


The lack of questions on the subject may be an indication of code smell here, but... Is it possible to write an extension method for a class and databind to that like you would a property?

The assumption is that I am provided with a class structure that I'm not able to fundamentally change, but I want to express a series of its boolean properties as a string for display purposes.

Simplified base class:

public class Transmission
{
    public int ID { get; set; }
    public bool Cancelled { get; set; }
    public bool Stored { get; set; }
    public bool Recorded { get; set; }
}

My extension method:

public static class Extensions
{
    public static string Status(this Transmission trans)
    {
        StringBuilder sb = new StringBuilder("|");
        if (trans.Cancelled)
            sb.Append("| Cancelled ");
        if (trans.Recorded)
            sb.Append("| Recorded ");
        if (trans.Stored)
            sb.Append("| Stored ");
        sb.Append("||");

        return sb.ToString();
    }
}

To add further complexity, I'm being passed a list of these things, and I'm trying to bind to a datagrid (with severely limited XAML experience).

<GroupBox Header="Here is an amazing list of results for you to violate horribly.">
    <DataGrid ItemsSource="{Binding Transmissions, Mode=OneWay}" AutoGenerateColumns="False">
         <DataGrid.Columns>
            <DataGridTextColumn Width="*" Header="Local ID" Binding="{Binding ID, Mode=OneWay}"/>
            <DataGridTextColumn Width="*" Header="Status" Binding="{Binding Status, Mode=OneWay}"/>
         </DataGrid.Columns>
    </DataGrid>
</GroupBox>

I've tested the code and was able to bind to ID without any difficulty. The 'Status' however, is not being picked up at all. Is there a trick to binding to an extension property? Or would it be more prudent to just write a decorator/facade class and bind to that?

解决方案

When you are passed the list of Transmission objects you can use the Façade pattern and store them in a container designed...

public class TransmissionContainer : INotifyPropertyChanged
{
    private readonly Transmission _transmission;
    public TransmissionContainer(Transmission transmission)
    {
        _transmission = transmission;
    }
    private int _id;
    public int Id
    {
        [DebuggerStepThrough]
        get { return _transmission.ID; }
        [DebuggerStepThrough]
        set
        {
            if (value != _transmission.ID)
            {
                _transmission.ID = value;
                OnPropertyChanged("Id");
            }
        }
    }
    public bool Cancelled
    {
        [DebuggerStepThrough]
        get { return _transmission.Cancelled }
        [DebuggerStepThrough]
        set
        {
            if (value != _transmission.Cancelled)
            {
                _transmission.Cancelled = value;
                OnPropertyChanged("Cancelled");
                OnPropertyChanged("Status");
            }
        }
    }
    public string Status
    {
        [DebuggerStepThrough]
        get
        {
            StringBuilder sb = new StringBuilder("|");
            if (_transmission.Cancelled)
                sb.Append("| Cancelled ");
            if (_transmission.Recorded)
                sb.Append("| Recorded ");
            if (_transmission.Stored)
                sb.Append("| Stored ");
            sb.Append("||");
            return sb.ToString();
        }
    }
    //
    // code in other properties here
    //
    #region INotifyPropertyChanged Implementation
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string name)
    {
        var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
    #endregion
}

This is a container class that creates a façade to which your Xaml can bind transparently. As shown, each of the exposed properties simply echoes back the value in the private instance of Transmission. Changes are relayed to the WPF binding engine via the INotifyPropertyChanged interface.

To create an instance you can construct it with the original Transmission class. To bind a collection of these containers, you can declare an ObservableCollection of type TransmissionContainer. Doing that means the list is bound in addition to the various changes in the properties.

In this approach, your 'extension' property is just another exposed property that has no setter. Note that changes to the other members that affect Status call the notification on behalf of the 'extension' property. Coding in the remaining members of the Transmission class should take about 20 minutes...

这篇关于可以将数据绑定到扩展方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆