2011-05-07 36 views
19

Sorunum var ve bu kadar basit bir sorunu nasıl çözeceğimi bilmiyorum, bunun gibi birçok noktaya sahibim, o zaman çözüm karmaşık olmamalı.Bunu ConverterParameter'a nasıl bağlarım?

Ayarlar ve ana XAML ile ana projem var.

<TextBlock Text="{Binding X.Y.Z, Converter={StaticResource ProbabilityConverter}, ConverterParameter=??????????????, Mode=OneWay}"/> 

Bu XAML dosyası ana projeden ana XAML dosyası tarafından yüklüyor: gibi

Ben Cilt Dönüştürücü ve XAML dosyası ile bağımlılık projesi var görünüyor.

Ben ConverterParameter için 's Ayar itibaren bir özelliğin değerini geçmelidir, bu parametreler, çalışma sırasında değişen olabilir, o zaman bu ben sadece bu durumda DependencyProperty için yapabileceği Binding, Binding olma zorunluluğudur.

Bu sorunu çözmek için DependencyProperty sarıcı bu ayar özelliğini yapmalı mıyım?

A 'Bağlama 'Bağlama' tip ait 'ConverterParameter' mülkiyet ayarlanamaz: i zamanında bu durum alacak BindingConverterParameter ayarlanan deneyin

. Bir 'Bağlama', DependencyObject öğesinin DependencyProperty öğesinde yalnızca olarak ayarlanabilir.

cevap

21

Herhangi bir özelliğe bağlanabilir, bu bir bağımlılık özelliği olmak zorunda değildir. Ancak, kullanıcı arayüzünüzün gerçekleştiğinde anında değişiklikleri yansıtmasını isterseniz, iki seçeneğiniz vardır:

  1. Özelliği, bir bağımlılık özelliği haline getirin.
  2. Özelliği korur ve özelliği değiştiğinde PropertyChanged olayını yükseltmek için INotifyPropertyChanged uygular.

DÜZENLEME: soruya düzenleyin belirttiği gibi

, bu ConverterParameter bağlamak mümkün değildir. Ancak MultiBinding'u kullanabilirsiniz. Örneğin, bir tarihe bağlanmak ve dönüştürücü kültür belirtimine bir parametre olarak vermek ve kültür değiştiğinde bağlamayı yenilemek istediğinizi varsayalım (bunun iyi bir fikir olduğundan emin değilim, ancak örnek olarak iyi bir şekilde çalıştığını varsayalım). Böyle yapabileceğini: Burada

<TextBlock> 
    <TextBlock.Resources> 
     <local:DateCultureConverter x:Key="converter" /> 
    </TextBlock.Resources> 
    <TextBlock.Text> 
     <MultiBinding Converter="{StaticResource converter}"> 
      <Binding Path="Date" /> 
      <Binding Path="Settings.Culture" /> 
     </MultiBinding> 
    </TextBlock.Text> 
</TextBlock> 

, hem Date ve Settings akım DataContext üzerinde özellikleridir. DateCultureConverter, IMultiValueConverter uygular ve muhtemelen, gerçek uygulamada hiyerarşinin birkaç düzeyindeki kaynaklara yerleştirirsiniz.

+0

sonra ben sonra ben iç içe olan bağlamaları sonra bağlama gerekir, sorun olmaz Sadece bağımlılık-mülk için ;-(bunu tekrar yapmaya çalışıyorum ve bu konuyu güncelle – Svisstack

+0

güncellendi, eklenen hata dizesi! – Svisstack

+0

@Svisstack, güncellenmiş yanıtı gör – svick

4

Aşağıdaki çözeltiler birini kullanabilirsiniz:

  1. BindableParameter

https://marlongrech.wordpress.com/2008/08/03/my-wish-came-true-i-can-now-use-databinding-in-a-converterparameter/

Bu sınıf entegre olmalıdır (normal bağlantısına + iliştirilmiş bir özellik ve MarkupExtension kullanılarak) BindableParameter ve BindableParameterExtension (aşağıya bakınız) ve daha sonra aşağıdaki gibi kullanabilirsiniz:

XAML olarak

:

xmlns:local="clr-namespace:BindableParameterExtension" 

    <local:SampleConverter x:Key="sampleConverter" /> 

    <StackPanel Orientation="Vertical"> 
     <TextBox Name="txtContent" Text="Text from txtContent" /> 
     <TextBox Name="txtParameter" Text="Text from txtParameter" /> 
     <TextBox Name="txtBindingSample" 
       Text="{Binding ElementName=txtContent, Path=Text, Converter={StaticResource sampleConverter}}" 
       local:BindableParameter.BindParameter="{local:BindableParameter TargetProperty=TextBox.Text, 
           Binding={Binding ElementName=txtParameter, Path=Text} }" /> 
    </StackPanel> 

Mülkiyet "TargetProperty": BindableParamerter ait

TargetProperty=TextBox.Text 

(bu durumda "TextBox.Text" olarak) orijinal ciltli özelliği ayarlanmalıdır.

Örnek-Dönüştürücü:

using System; 
using System.Windows.Data; 

namespace BindableParameterExtension 
{ 
    public class SampleConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      if (value != null && parameter != null) 
      { 
       return value.ToString() + ", " + parameter.ToString(); 
      } 
      return null; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      if (value is string && parameter is string) 
      { 
       string text1 = value as string; 
       string textParamter = parameter as string; 

       return text1.Replace(textParamter, ""); 
      } 
      return value; 
     } 
    } 
}  

parametresi "dönüştürme" olarak kullanılabilir ve "ConvertBack" yöntemi (faydalı bir görünüşüdür modeli bağlamak için).

Sınıf BindableParameter ve BindableParameterExtension

/* 
* Copyright - Everyone can use this code for any reason yet if you find a bug, I do not hold myself responsable :D 
*/ 

using System.Windows.Data; 
using System.Windows.Markup; 

namespace BindableParameterExtension 
{ 
    /// <summary> 
    /// BindableParameter is the class that changes the ConverterParameter Value 
    /// This must inherit from freezable so that it can be in the inheritance context and thus be able to use the DataContext and to specify ElementName binding as a ConverterParameter 
    /// http://www.drwpf.com/Blog/Default.aspx?tabid=36&EntryID=36 
    /// </summary> 
    public class BindableParameter : Freezable 
    { 
     #region fields 
     //this is a hack to trick the WPF platform in thining that the binding is not sealed yet and then change the value of the converter parameter 
     private static FieldInfo isSealedFieldInfo; 
     #endregion 

     #region Properties 
     #region Parameter 

     /// <summary> 
     /// Parameter Dependency Property 
     /// </summary> 
     public static readonly DependencyProperty ParameterProperty = 
      DependencyProperty.Register("Parameter", typeof(object), typeof(BindableParameter), 
       new FrameworkPropertyMetadata((object)null, 
        (d, e) => 
        { 
         BindableParameter param = (BindableParameter)d; 
         //set the ConverterParameterValue before calling invalidate because the invalidate uses that value to sett the converter paramter 
         param.ConverterParameterValue = e.NewValue; 
         //update the converter parameter 
         InvalidateBinding(param); 
        } 
        )); 

     /// <summary> 
     /// Gets or sets the Parameter property. This dependency property 
     /// indicates .... 
     /// </summary> 
     public object Parameter 
     { 
      get { return (object)GetValue(ParameterProperty); } 
      set { SetValue(ParameterProperty, value); } 
     } 

     #endregion 

     #region BindParameter 

     /// <summary> 
     /// BindParameter Attached Dependency Property 
     /// </summary> 
     public static readonly DependencyProperty BindParameterProperty = 
      DependencyProperty.RegisterAttached("BindParameter", typeof(BindableParameter), typeof(BindableParameter), 
       new FrameworkPropertyMetadata((BindableParameter)null, 
        new PropertyChangedCallback(OnBindParameterChanged))); 

     /// <summary> 
     /// Gets the BindParameter property. This dependency property 
     /// indicates .... 
     /// </summary> 
     public static BindableParameter GetBindParameter(DependencyObject d) 
     { 
      return (BindableParameter)d.GetValue(BindParameterProperty); 
     } 

     /// <summary> 
     /// Sets the BindParameter property. This dependency property 
     /// indicates .... 
     /// </summary> 
     public static void SetBindParameter(DependencyObject d, BindableParameter value) 
     { 
      d.SetValue(BindParameterProperty, value); 
     } 

     /// <summary> 
     /// Handles changes to the BindParameter property. 
     /// </summary> 
     private static void OnBindParameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      FrameworkElement element = d as FrameworkElement; 
      if (element == null) 
       throw new InvalidOperationException("BindableParameter can be applied to a FrameworkElement only"); 

      BindableParameter parameter = (BindableParameter)e.NewValue; 
      element.Initialized += delegate 
      { 
       parameter.TargetExpression = BindingOperations.GetBindingExpression(element, parameter.TargetProperty); 
       parameter.TargetBinding = BindingOperations.GetBinding(element, parameter.TargetProperty); 

       //update the converter parameter 
       InvalidateBinding(parameter); 
      }; 
     } 

     #endregion 

     public object ConverterParameterValue { get; set; } 

     public BindingExpression TargetExpression { get; set; } 

     public Binding TargetBinding { get; private set; } 

     /// <summary> 
     /// Gets the object being bound 
     /// </summary> 
     public DependencyObject TargetObject { get; private set; } 

     /// <summary> 
     /// Gets the dependency property being bound 
     /// </summary> 
     public DependencyProperty TargetProperty { get; internal set; } 
     #endregion 

     /// <summary> 
     /// Static constructor to get the FieldInfo meta data for the _isSealed field of the BindingBase class 
     /// </summary> 
     static BindableParameter() 
     { 
      //initialize the field info once 
      isSealedFieldInfo = 
       typeof(BindingBase).GetField("_isSealed", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); 

      if (isSealedFieldInfo == null) 
       throw new InvalidOperationException("Oops, we have a problem, it seems like the WPF team decided to change the name of the _isSealed field of the BindingBase class."); 

     } 

     private static void InvalidateBinding(BindableParameter param) 
     { 
      if (param.TargetBinding != null && param.TargetExpression != null) 
      { 
       //this is a hack to trick the WPF platform in thining that the binding is not sealed yet and then change the value of the converter parameter 
       bool isSealed = (bool)isSealedFieldInfo.GetValue(param.TargetBinding); 

       if (isSealed)//change the is sealed value 
        isSealedFieldInfo.SetValue(param.TargetBinding, false); 

       param.TargetBinding.ConverterParameter = param.ConverterParameterValue; 

       if (isSealed)//put the is sealed value back as it was... 
        isSealedFieldInfo.SetValue(param.TargetBinding, true); 

       //force an update to the binding 
       param.TargetExpression.UpdateTarget(); 
      } 
     } 

     #region Freezable Stuff 
     protected override Freezable CreateInstanceCore() 
     { 
      //throw new NotImplementedException(); 
      //return _bindableParam; 

      return this; 
     } 
     #endregion 

    } 

    /// <summary> 
    /// Markup extension so that it is easier to create an instance of the BindableParameter from XAML 
    /// </summary> 
    [MarkupExtensionReturnType(typeof(BindableParameter))] 
    public class BindableParameterExtension : MarkupExtension 
    { 
     /// <summary> 
     /// Gets or sets the Dependency property you want to change the binding's ConverterParameter 
     /// </summary> 
     public DependencyProperty TargetProperty { get; set; } 

     /// <summary> 
     /// Gets or sets the Binding that you want to use for the converter parameter 
     /// </summary> 
     public Binding Binding { get; set; } 

     /// <summary> 
     /// constructor that accepts a Dependency Property so that you do not need to specify TargetProperty 
     /// </summary> 
     /// <param name="property">The Dependency property you want to change the binding's ConverterParameter</param> 
     public BindableParameterExtension(DependencyProperty property) 
     { 
      TargetProperty = property; 
     } 

     public BindableParameterExtension() 
     { } 

     public override object ProvideValue(IServiceProvider serviceProvider) 
     { 
      _bindableParam = new BindableParameter(); 
      //set the binding of the parameter 
      BindingOperations.SetBinding(_bindableParam, BindableParameter.ParameterProperty, Binding); 
      _bindableParam.TargetProperty = TargetProperty; 
      return _bindableParam; 
     } 

     private BindableParameter _bindableParam; 

    } 
} 
(URL (benim kodu) yukarıya bakınız)
  • ObjectReference
      :

    http://drwpf.com/blog/2007/09/02/supplying-an-object-reference-in-the-constructorparameters-collection-of-an-objectdataprovider/

    You ObjectReference sınıfı:

    XAML olarak

    http://www.drwpf.com/blog/Portals/0/Code/ObjectReference.cs.txt

    :

    xmlns:local="clr-namespace:WpfMarkupExtension" 
    
    <local:SampleConverter x:Key="sampleConverter" /> 
    
    <StackPanel Orientation="Vertical"> 
        <TextBox Name="txtContent" Text="Text from txtContent" /> 
        <TextBox Name="txtParameter" Text="Text from txtParameter" local:ObjectReference.Declaration="{local:ObjectReference txtParam}" /> 
        <TextBox Name="txtBindingSample" 
          Text="{Binding ElementName=txtContent, Path=Text, 
              Converter={StaticResource sampleConverter}, 
              ConverterParameter={local:ObjectReference txtParam}}" /> 
    </StackPanel> 
    

    snipped:

    ConverterParameter={local:ObjectReference txtParam}}" 
    

    bu nesne başvurusu alır:

    local:ObjectReference.Declaration="{local:ObjectReference txtParam}" 
    

    bir statik sözlükte başvuru ve parça üretilir Sözlük -> burada bağlama yok, sözlük fi ayrıştırma zamanı.

    Örnek-Dönüştürücü:

    using System; 
    using System.Windows.Controls; 
    using System.Windows.Data; 
    
    namespace WpfMarkupExtension 
    { 
        public class SampleConverter : IValueConverter 
        { 
         public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
         { 
          if (value != null && parameter is TextBox) 
          { 
           return value.ToString() + ", " + ((TextBox)parameter).Text; 
          } 
          return null; 
         } 
    
         public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
         { 
          if (value is string && parameter is TextBox) 
          { 
           string text1 = value as string; 
           string textParamter = ((TextBox)parameter).Text; 
    
           return text1.Replace(textParamter, ""); 
    
          } 
    
          return value; 
         } 
        } 
    } 
    
      (özel bağlama sözdizimi kullanılarak)
    1. Bindable Dönüştürücü Parametresi: XAML

    http://www.codeproject.com/Articles/456589/Bindable-Converter-Parameter

    :

    xmlns:local="clr-namespace:BcpBindingExtension" 
    
        <local:SampleConverter x:Key="sampleConverter" /> 
    
        <StackPanel Orientation="Vertical"> 
         <TextBox Name="txtContent" Text="Text from txtContent" /> 
         <TextBox Name="txtParameter" Text="Text from txtParameter" /> 
         <TextBox Name="txtBindingSample"> 
           <TextBox.Text> 
            <local:BcpBinding Path="Text" ElementName="txtContent" 
                 Converter="{StaticResource sampleConverter}" 
                 ConverterParameters="Binding Path=Text ElementName=txtParameter" 
                 Mode="TwoWay"/> 
           </TextBox.Text> 
         </TextBox> 
        </StackPanel> 
    

    Numune-Dönüştürücü: i Normal özelliğine bağlayabilir eğer ben inotitypropertychanged uygulamasıyla sınıf var ;-) ama derleyici diyor çünkü

    using System; 
    using System.Windows.Data; 
    
    namespace BcpBindingExtension 
    { 
        public class SampleConverter : IValueConverter 
        { 
         public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
         { 
          if (value != null && parameter is object[] && ((object[])parameter).Length > 0) 
          { 
           return value.ToString() + ", " + ((object[])parameter)[0].ToString(); 
          } 
          return null; 
         } 
    
         public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
         { 
          if (value is string && parameter is object[] && ((object[])parameter).Length > 0) 
          { 
           string text1 = value as string; 
           string textParamter = ((object[])parameter)[0] as string; 
    
           return text1.Replace(textParamter, ""); 
    
          } 
    
          return value; 
         } 
        } 
    } 
    
  • İlgili konular