سؤال

لدي الدرجة EmployeeViewModel مع 2 خصائص "الاسم الأول" و "اسم العائلة".الطبقة أيضا قاموس مع التغيرات في الخصائص.(فئة تنفذ INotifyPropertyChanged و IDataErrorInfo كل شيء على ما يرام.

في رأيي هناك مربع نص:

<TextBox x:Name="firstNameTextBox" Text="{Binding Path=FirstName}" />

كيف يمكنني تغيير لون خلفية مربع النص ، إذا كانت القيمة الأصلية تغير ؟ فكرت في إنشاء الزناد الذي يحدد لون الخلفية ولكن ما يجب ربط?أنا لا أريد أن إنشاء خاصية إضافية لكل التحكم الذي يحمل الدولة هيتر واحد غيرت أم لا.

Thx

هل كانت مفيدة؟

المحلول

ومجرد استخدام MultiBinding مع نفس العقار مرتين ولكن لديها وضع = مرة واحدة على واحدة من الارتباطات. مثل هذا:

Public Class MVCBackground
    Implements IMultiValueConverter

    Public Function Convert(ByVal values() As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IMultiValueConverter.Convert
        Static unchanged As Brush = Brushes.Blue
        Static changed As Brush = Brushes.Red

        If values.Count = 2 Then
            If values(0).Equals(values(1)) Then
                Return unchanged
            Else
                Return changed
            End If
        Else
            Return unchanged
        End If
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetTypes() As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object() Implements System.Windows.Data.IMultiValueConverter.ConvertBack
        Throw New NotImplementedException()
    End Function
End Class

وفي XAML:

<TextBox Text="{Binding TestText}">
    <TextBox.Background>
        <MultiBinding Converter="{StaticResource BackgroundConverter}">
            <Binding Path="TestText"    />
            <Binding Path="TestText" Mode="OneTime" />
        </MultiBinding>
    </TextBox.Background>
</TextBox>

ولا خصائص إضافية أو منطق المطلوبة وربما كنت قد لف كل شيء في تمديد العلامات الخاصة بك. نأمل أن يساعد.

نصائح أخرى

سوف تحتاج إلى استخدام قيمة تحويل (تحويل سلسلة الإدخال إلى اللون الناتج) و أبسط حل يتضمن إضافة واحد على الأقل أكثر الممتلكات الخاصة بك EmployeeViewModel.تحتاج إلى إجراء نوع من الافتراضي أو OriginalValue مكان الإقامة ، ومقارنة ضد ذلك.وإلا كيف لك أن تعرف ما هي "القيمة الأصلية" ؟ لا يمكنك معرفة ما إذا كان تغير قيمة ما لم يكن هناك شيء القابضة القيمة الأصلية لمقارنة ضد.

لذا ربط الخاصية text ومقارنة سلسلة الإدخال إلى القيمة الأصلية على نموذج عرض.إذا كان قد تغير ، إعادة إبراز لون الخلفية.إذا كانت مباريات العودة العادي لون الخلفية.سوف تحتاج إلى استخدام متعدد ملزمة إذا كنت ترغب في مقارنة الاسم الأول و اسم العائلة معا من واحد مربع نص.

وقد شيدت مثال يوضح كيف أن هذا يمكن أن تعمل:

<Window x:Class="TestWpfApplication.Window11"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestWpfApplication"
Title="Window11" Height="300" Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
    <local:ChangedDefaultColorConverter x:Key="changedDefaultColorConverter"/>
</Window.Resources>
<StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock>Default String:</TextBlock>
        <TextBlock Text="{Binding Path=DefaultString}" Margin="5,0"/>
    </StackPanel>
    <Border BorderThickness="3" CornerRadius="3"
            BorderBrush="{Binding ElementName=textBox, Path=Text, Converter={StaticResource changedDefaultColorConverter}}">
        <TextBox Name="textBox" Text="{Binding Path=DefaultString, Mode=OneTime}"/>
    </Border>
</StackPanel>

و هنا هو رمز-خلف النافذة:

/// <summary>
/// Interaction logic for Window11.xaml
/// </summary>
public partial class Window11 : Window
{
    public static string DefaultString
    {
        get { return "John Doe"; }
    }

    public Window11()
    {
        InitializeComponent();
    }
}

وأخيرا ها هو المحول الذي تستخدمه:

public class ChangedDefaultColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string text = (string)value;
        return (text == Window11.DefaultString) ?
            Brushes.Transparent :
            Brushes.Yellow;
    }

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

وعلى الرغم من أنني ملفوفة الحدود حول النص (لأنني أعتقد أن تبدو أفضل قليلا) ، على خلفية ملزمة يمكن أن يتم بنفس الطريقة:

<TextBox Name="textBox" Text="{Binding Path=DefaultString, Mode=OneTime}"
         Background="{Binding ElementName=textBox, Path=Text, Converter={StaticResource changedDefaultColorConverter}}"/>

إذا كنت تستخدم نموذج MVVM، عليك أن تنظر في ViewModels وجود دور محولات بين نموذج عرض و.

لا يتوقع من ViewModel أن يكون الملحد تماما من وجود UI في كل شيء، ولكن أن يكون الملحد أي محددة UI.

وهكذا، وViewModel يمكن (ويجب) أن يكون وظيفة العديد من محولات وقت ممكن. ومثال عملي هنا سيكون هذا:

هل واجهة يحتاجون إليها لمعرفة ما إذا كان النص يساوي سلسلة الافتراضي؟

إذا كان الجواب <م> نعم ، انها سببا كافيا لتنفيذ خاصية IsDefaultString على ViewModel.

public class TextViewModel : ViewModelBase
{
    private string theText;

    public string TheText
    {
        get { return theText; }
        set
        {
            if (value != theText)
            {
                theText = value;
                OnPropertyChanged("TheText");
                OnPropertyChanged("IsTextDefault");
            }
        }
    }

    public bool IsTextDefault
    {
        get
        {
            return GetIsTextDefault(theText);
        }
    }

    private bool GetIsTextDefault(string text)
    {
        //implement here
    }
}

وبعد ذلك ربط TextBox مثل هذا:

<TextBox x:Name="textBox" Background="White" Text="{Binding Path=TheText, UpdateSourceTrigger=LostFocus}">
    <TextBox.Resources>
        <Style TargetType="TextBox">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsTextDefault}" Value="False">
                    <Setter Property="TextBox.Background" Value="Red"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBox.Resources>
</TextBox>

وهذه تنتشر النص إلى ViewModel على TextBox فقدان التركيز، الذي يؤدي إلى إعادة حساب IsTextDefault. إذا كنت بحاجة للقيام بذلك في الكثير من الأحيان أو لكثير من الخصائص، يمكن لك حتى سلق بعض الفئة الأساسية مثل DefaultManagerViewModel.

هل يمكن أن تضيف إلى خصائص منطقية ViewModel الخاصة بك مثل IsFirstNameModified وIsLastNameModified، واستخدام مشغل لتغيير الخلفية إذا كان النص وفقا لهذه الخصائص. أو هل يمكن ربط Background إلى هذه الخصائص، مع تحويل وترجع Brush من منطقي ...

وهناك طريقة diferent كاملة سيكون لعدم تنفيذ INotifyPropertyChanged وبدلا من ذلك ينزل من DependencyObject أو UIElement

وانهم تنفيذ الربط باستخدام DependencyProperty تستطيع استخدام الحدث فقط معالج حدث واحد وe.Property المستخدم للعثور على نص RIGTH

وأنا متأكد من e.NewValue! = الاختيار e.OldValue لا لزوم لها باعتبارها ملزمة لا ينبغي أن يتغير. أنا أيضا أصدق قد تكون هناك وسيلة لتنفيذ الربط بحيث dependecyObject هو النص وليس وجوه الخاص بك ...

وتحرير إذا كنت ترث بالفعل من أي فئة WPF (مثل التحكم أو usercontrol) وربما كنت لا بأس به، لا تحتاج لتغيير UIElement لأن معظم WPF ترث من تلك الفئة

وبعد ذلك يمكن أن يكون لديك:

using System.Windows;
namespace YourNameSpace
{
class PersonViewer:UIElement
{

    //DependencyProperty FirstName
    public static readonly DependencyProperty FirstNameProperty =
        DependencyProperty.Register("FirstName", typeof (string), typeof (PersonViewer),
                                    new FrameworkPropertyMetadata("DefaultPersonName", FirstNameChangedCallback));

    public string FirstName {
        set { SetValue(FirstNameProperty, value); }
        get { return (string) GetValue(FirstNameProperty); }
    }

    private static void FirstNameChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) {

        PersonViewer owner = d as PersonViewer;
        if (owner != null) {
            if(e.NewValue != e.OldValue && e.NewValue != "DefaultPersonName" ) {

                //Set Textbox to changed state here

            }
        }

    }

    public void AcceptPersonChanges() {

        //Set Textbox to not changed here

    }

 }
}

وهناك تباين من الإجابة الماضية يمكن أن يكون أن يكون دائما في حالة تعديل ما لم تكن القيمة هي القيمة الافتراضية.

 <TextBox.Resources>
    <Style TargetType="{x:Type TextBox}">

        <Style.Triggers>
            <Trigger Property="IsLoaded" Value="True">
                <Setter Property="TextBox.Background" Value="Red"/>
            </DataTrigger>
        </Style.Triggers>

        <Style.Triggers>
            <DataTrigger Binding="{Binding RelativeSource Self}, Path=Text" Value="DefaultValueHere">
                <Setter Property="TextBox.Background" Value=""/>
            </DataTrigger>
        </Style.Triggers>

    </Style>
</TextBox.Resources>

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top