Как данные связывают результат метода представления модели со свойством TextBox? - PullRequest
6 голосов
/ 04 февраля 2012

В моей view-модели и модели у меня есть метод с сигнатурой bool IsPropertyReadOnly(string propertyName). Этот метод определяет, может ли зарегистрированный в данный момент пользователь редактировать значение свойства. Несколько пользователей смогут редактировать значения свойств, а большинство других будет иметь доступ только для чтения.

Вместо создания свойства, возвращающего состояние только для чтения каждого из свойств модели, я хочу связать результат IsPropertyReadOny со свойством TextBox.IsReadOnly.

Вот как я представляю синтаксис:

<TextBox Text="{Binding Address, Mode=TwoWay}" 
         IsReadOnly="{Binding MethodName=IsPropertyReadOnly MethodParameter=Address}"
/>

DataContext содержит модель представления, поэтому в основном мне нужно связать IsReadOnly с результатом вызова ((Class)this.DataContext).IsPropertyReadOnly("Address")

Существует много документации по использованию ObjectDataProvider, но поставщик данных объекта создает новый экземпляр объекта, который мне не нужен. Более того, чтобы использовать существующий экземпляр, я должен выполнить присваивание в коде. Опять же, не то, что я хочу сделать.

Из моего исследования кажется, что решение, которое наследуется от Binding или MarkupExtension, лучше подходит для моих нужд.

Любая помощь будет принята с благодарностью.

Ответы [ 3 ]

4 голосов
/ 06 февраля 2012

Я предлагаю использовать конвертер.Вот пример.Предположим, у вас есть простой класс ViewModel:

class ViewModel
{
    public string Read
    { get; set; }

    public string ReadWrite
    { get; set; }

    public bool IsPropertyReadOnly(string propertyName)
    {
        return propertyName != "ReadWrite";
    }
}

Чтобы решить вашу проблему, вам нужно написать конвертер, такой как:

public class Converter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var vm = value as ViewModel;
        var functionName = (string)parameter;

        var result = vm.IsPropertyReadOnly(functionName);
        return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException("This method should never be called");
    }
}

И это все;теперь вы можете использовать этот конвертер в XAML, например:

<Window.Resources>
    <temp:Converter x:Key="ReadOnlyMethodConverter"/>
</Window.Resources>
<StackPanel>
    <TextBox Text="{Binding Read, Mode=TwoWay}" 
             IsReadOnly="{Binding Path=.,
        Converter={StaticResource ReadOnlyMethodConverter}, ConverterParameter=Read}"
    />
    <TextBox Text="{Binding ReadWrite, Mode=TwoWay}" 
             IsReadOnly="{Binding Path=.,
        Converter={StaticResource ReadOnlyMethodConverter}, ConverterParameter=ReadWrite}"
    />
</StackPanel>

А в коде позади мы просто создаем ViewModel и устанавливаем его как DataContext:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }
}
4 голосов
/ 06 февраля 2012

Более того, чтобы использовать существующий экземпляр, я должен выполнить присваивание в коде. Опять же, не то, что я хочу сделать.

Это неправда, однако ваш выбор будет ограничен.


Как насчет индексаторов?

private readonly Dictionary<string, bool> _PropertyReadOnlyDictionary = new Dictionary<string, bool>();
public Dictionary<string, bool> PropertyReadOnlyDictionary { get { return _PropertyReadOnlyDictionary; } }
<TextBox Text="{Binding Address, Mode=TwoWay}"
        IsReadOnly="{Binding PropertyReadOnlyDictionary[Address]}" />

Конечно, вы можете обернуть свой метод в новый класс, который также разрешает доступ через индексатор, если вы не хотите использовать словарь.

private readonly PropertyIsReadOnlyResolver _PropertyIsReadOnlyResolver = new PropertyIsReadOnlyResolver();
public PropertyIsReadOnlyResolver PropertyIsReadOnlyResolver { get { return _PropertyIsReadOnlyResolver; } }
public class PropertyIsReadOnlyResolver
{
    public bool this[string propertyName]
    {
        get
        {
            return IsPropertyReadOnly(propertyName);
        }
    }

    public bool IsPropertyReadOnly(string propertyName)
    {
        //...
    }
}
<TextBox Text="{Binding Address, Mode=TwoWay}"
        IsReadOnly="{Binding PropertyIsReadOnlyResolver[Address]}" />
0 голосов
/ 04 февраля 2012

Вы должны быть в состоянии сделать это, используя ObjectDataProvider для выполнения метода, а затем привязать присоединенное свойство к возвращаемому значению провайдера.

Сначала вам нужно настроить провайдера как ресурс:

<Window.Resources>
  <ObjectDataProvider x:Key="readOnlyProvider" ...>
    <ObjectDataProvider.MethodParameters>
      ...
    </ObjectDataProvider.MethodParameters>
  </ObjectDataProvider>
</Window.Resources>

Затем используйте провайдера в качестве источника привязки прикрепленного свойства:

<TextBox Text="{Binding PoolNum, Mode=OneWay}" Windows:AttachedProperties.IsReadOnlyOn="{Binding Source={StaticResource readOnlyProvider}}" />

Сложной частью этого процесса будет «передача» значения в ObjectDataProviders.MethodParameters,Это можно сделать в XAML, и есть несколько ресурсов, чтобы показать вам, как это делается;вот для начала: http://weblogs.asp.net/psheriff/archive/2010/02/23/bind-objectdataprovider-method-parameters-in-wpf.aspx

ОБНОВЛЕНИЕ

Для вашего комментария, вот два способа, которыми ObjectDataProvider может выполнить метод для вашего представления DataContextбез создания нового объекта.

Сначала сделайте метод модели представления статичным и используйте свойство ObjectType:

<ObjectDataProvider x:Key="readOnlyProvider"
  ObjectType="{x:local MyDataContext}"
  MethodName="IsPropertyReadOnly">
  ...
</ObjectDataProvider>

Или установите ObjectInstance поставщика в представлениеDataContext при загрузке представления:

public class MyWindow : Window
{
  public MyWindow()
  {
    InitializeComponent();

    var readOnlyProvider = this.Resources["readOnlyProvider"] as ObjectDataProvider;
    readOnlyProvider.ObjectInstance = this.DataContext;
  }
}

Нет способа привязки к методам в XAML, и единственные известные мне обходные пути использования ObjectDataProvider.

...