2012-02-04 12 views
5

W moim modelu widoku i modelu mam metodę z podpisem bool IsPropertyReadOnly(string propertyName). Ta metoda określa, czy aktualnie zalogowany użytkownik może edytować wartość propryny. Kilku użytkowników będzie mogło edytować wartości właściwości, a większość z nich będzie miała dostęp tylko do odczytu.W jaki sposób dane wiążą wynik metody modelu widoku z właściwością TextBox?

Zamiast tworzyć właściwość zwracającą status tylko do odczytu dla każdej właściwości modelu, chcę powiązać wynik właściwości IsPropertyReadOny z właściwością TextBox.IsReadOnly.

ten sposób wyobrażam sobie składnię:

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

DataContext zawiera widok model, więc w zasadzie muszę wiązać IsReadOnly w wyniku wezwania ((Class)this.DataContext).IsPropertyReadOnly("Address")

Jest wiele dokumentacja przy użyciu ObjectDataProvider, ale dostawca danych obiektu tworzy nową instancję obiektu, która nie jest tym, czego chcę. Co więcej, aby użyć istniejącej instancji, muszę wykonać zadanie z opóźnieniem kodu. Ponownie, nie to, co chcę zrobić.

Z moich badań wynika, że ​​rozwiązanie, które dziedziczy po Binding lub MarkupExtension, lepiej pasuje do moich potrzeb.

Każda pomoc zostanie bardzo doceniona.

+0

Tutaj może być odpowiedź na swoje pytanie (ostatnią odpowiedź, która używa konwertera) [? Wiążą się metody w WPF] (http://stackoverflow.com/questions/ 502250/bind-to-a-method-in-wpf) –

Odpowiedz

4

Proponuję użyć konwertera. Oto przykład.Załóżmy, że masz prostą klasę ViewModel:

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

    public string ReadWrite 
    { get; set; } 

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

Aby rozwiązać problem trzeba napisać konwerter, takich jak:

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"); 
    } 
} 

i to wszystko; Teraz można korzystać z tego konwertera w XAML, jak:

<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> 

I w kodzie opóźnieniem po prostu utworzyć ViewModel i ustawić go jako DataContext:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = new ViewModel(); 
    } 
} 
+0

Mimo że użyłem sugestii H.B. w innej odpowiedzi, przyjąłem i głosowałem na tę odpowiedź, ponieważ myślę, że to w pełni odpowiada na pytanie dotyczące wiązania z metodą z parametrami w modelu widoku. – AMissico

+3

Myślę, że w poprzednim komentarzu było zbyt wiele odpowiedzi. : O) – AMissico

0

Powinieneś być w stanie to zrobić, używając ObjectDataProvider, aby wykonać metodę, a następnie powiązać załączoną właściwość z wartością zwracaną przez dostawcę.

Najpierw trzeba skonfigurować dostawcę jako zasób:

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

następnie użyć dostawcę jako źródło swojej załączonym własności wiązania:

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

Najtrudniejszą częścią tego procesu będzie "przekazywać" wartość do ObjectDataProviders.MethodParameters. Można to zrobić w XAML i istnieje kilka zasobów, które pokazują, jak to się robi; oto jeden zacząć: http://weblogs.asp.net/psheriff/archive/2010/02/23/bind-objectdataprovider-method-parameters-in-wpf.aspx

UPDATE

Per Twojego komentarza, tu są dwa sposobów ObjectDataProvider można wykonać metodą na Twój widok na DataContext bez tworzenia nowego obiektu.

Po pierwsze, upewnij metoda widok modelu statycznego i użyć właściwości ObjectType:

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

Lub ustaw ObjectInstance dostawcy do widoku na DataContext gdy widok ładunki:

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

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

Nie nie ma sposobu na powiązanie metod w XAML i jedyne obejścia, o których wiem, że używają ObjectDataProvider.

+0

Ale nie chcę, aby obiekt ObjectDataProvider tworzył nowy obiekt. Byłoby miło, gdybym mógł ustawić obiekt dostawcy. – AMissico

4

Ponadto, aby użyć istniejącej instancji I musi wykonać zadanie z opóźnieniem kodu. Ponownie, nie to, co chcę zrobić.

To nie prawda, ale Twoje wybory będą ograniczone.


Co z indeksatorami?

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]}" /> 

Można oczywiście zawinąć metodę w nowej klasie, która umożliwia dostęp za pośrednictwem indekser jak dobrze, jeśli nie chcesz używać słownika.

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

Interesujące, najpierw skorzystaliśmy z indeksera. Zdecydowałem się na to, ponieważ potrzebujemy użyć 'IDataErrorInfo'. Lubię pierwszy indeksator ze słownikiem, ponieważ lepiej pasuje do naszej implementacji. – AMissico

+0

Wykorzystaliśmy implementację PropertyReadOnlyDictionary i doskonale zintegrowaliśmy ją z naszym projektem. Dziękuję Ci bardzo. – AMissico

+0

@ Amissico: Miło to słyszeć :) –

Powiązane problemy