2013-04-29 27 views
2

我正在使用OneWayToSource綁定,它似乎總是將我的源屬性設置爲null。爲什麼?這是我的麻煩,因爲我需要源屬性中的目標屬性的值,而不是null。OneWayToSource窘境

這裏是我的代碼:

MyViewModel.cs:

public class MyViewModel 
{ 
    private string str; 

    public string Txt 
    { 
     get { return this.str; } 
     set { this.str = value; } 
    } 
} 

MainWindow.cs:

public MainWindow() 
{ 
    InitializeComponent(); 
    MyViewModel vm = new MyViewModel(); 
    vm.Txt = "123"; 
    this.DataContext = vm; 
} 

MainWindow.xaml:

<Window x:Class="OneWayToSourceTest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525" 
     xmlns:local="clr-namespace:OneWayToSourceTest"> 
     <Grid> 
     <local:MyButton Content="{Binding Path=Txt, Mode=OneWayToSource}"/> 
     </Grid> 
</Window> 

MyButton.cs:

public class MyButton : Button 
{ 
    public MyButton() 
    { 
     this.Content = "765"; 
    } 
} 

target屬性是MyButton.Content。源屬性是MyViewModel.TxtTxt屬性應該設置爲「765」,但它是空的。

爲什麼我會收到空​​值而不是765?

編輯:

請看看裏面MyButton構造。其實如果你會使用簡單的TwoWay它會起作用。我測試了它,它與構造函數中設置的內容無關。它的東西與OneWayToSource綁定我猜。

我們解釋我是如何用TwoWay綁定,我沒有通過調用setvalue方法,但再包裝或更好的內部設置構造函數中的DP值表示getter和setter我沒有提供任何二傳手因此爲什麼我做了我的TwoWay有點像它的OneWayToSource。我做了它來測試它的構造函數是否有錯。我認爲viewmodel內的屬性值爲765,所以這就是我的意思是TwoWay綁定。我只是測試它是否是控件構造函數。它的一切都很好,在構造函數中設置一個值。

通過隱藏二傳手我的意思是 集合{}

+0

您是否收到任何BindingErrors? – Jehof 2013-04-29 13:33:18

+0

不,我不。 : - (( – 2013-04-29 13:33:54

回答

4

myButton的被通過的InitializeComponent DataContext的實例之前設置的,所以結合是沒有生效時,它的構造器運行。嘗試設置一個值點擊按鈕。

+0

我不能強制用戶點擊一個按鈕來設置數值:) – 2013-04-29 14:31:05

+1

可能不是,但我已經向你解釋爲什麼它不能正常工作,非常感謝你的支持!! – johndsamuels 2013-04-29 14:34:46

+0

When datacontext沒有設置,Txt的值應該是123.請再次查看我的代碼,一旦設置了DataContext,綁定應該將Txt的值更新爲765.雖然問題是一旦綁定更新了值,值我很抱歉,但不管是在InitializeComponent之前還是之後,它仍然不能與OneWayToSource一起工作。請再次看看我的問題。我編輯它 – 2013-04-29 14:38:34

1

其實如果你會使用簡單的雙向它會工作。

我不能複製這個。根據您提供的代碼,如果您使用TwoWay綁定模式,則視圖模型Txt屬性將等於「123」,它是在您的MainWindows構造函數中給出的值。

我測試了它和它無關的內容設定內部構造

雷切爾已經指出的那樣,XAML綁定清除本地值。在之後發生綁定您的按鈕構造函數代碼被運行。綁定然後從依賴項屬性的元數據中檢索它的默認值。通過在綁定建立後(例如在Loaded事件中)在更合適的時間設置該值,可以很容易地解決這個問題。

這個簡單的修改將提供所要的結果:

public class MyButton : Button 
{ 
    public MyButton() 
    { 
     this.Loaded += MyButton_Loaded; 
    } 

    void MyButton_Loaded(object sender, RoutedEventArgs e) 
    { 
     this.Content = "765"; 
    } 
} 

Rachels回答還提供了製備這種工作(重寫屬性默認元數據)的替代方法。

爲什麼每次有人使用OneWayToSource綁定後將initalizatin設置爲 ?它對我沒有意義。

我認爲這對你沒有意義的原因是因爲你的TwoWay綁定測試不符合你的想法。

使用OneWayToSource結合:

使用OneWayToSource結合下面發生的事情:

  1. 你在它的構造函數設置MyButton.Content爲 「123」。
  2. 您正在設置您的XAML中的OneWayToSource綁定。這清除您設定的值。
  3. 該綁定從屬性元數據中檢索默認屬性值(null),並將ViewModel.Txt屬性設置爲等於此值。

如果您在按鈕加載的事件中設置了MyButton.Content屬性,則發生上述事件後,您的屬性將設置爲您希望的值。

您可以通過在MyViewModel.Txt屬性獲取器中放置斷點來驗證這一點。該值將按順序設置爲「123」,null和「756」。

使用雙向綁定:

現在,如果你要改變你的XAML使用TwoWay結合會發生以下情況:

  1. 你在它的構造函數設置MyButton.Content爲「123」。
  2. 您正在XAML中設置TwoWay綁定。這清除您設定的值。
  3. 你的控制值(MyButton.Content)使用在這種情況下是你的ViewModels Txt屬性導致在MyButton.Content屬性等於「123」更新。
+0

我不是一個不知道爲什麼只是使用事物的粉絲。在這種情況下,我只需要相信你們。至於我已經說過我的自定義雙向綁定的例子,我成功地證明了它不是構造函數。然而,讓我們接受這個答案。謝謝 – 2013-04-29 19:01:27

8

Content屬性只能設置爲一個值,你是更換值「756」具有約束力。

正如我在my answer到您的其他問題向你指出,WPF運行順序代碼:

  • 正常 - 構造函數這裏
  • 的DataBind
  • 運行渲染
  • 加載

因此,首先完成的是您的MainWindow構造函數運行。這將創建按鈕,該按鈕調用Button的構造函數,並將Button.Content設置爲「765」。

但是,在XAML中爲Button指定了不同的Content屬性 - 一個綁定。因此,您的按鈕對象被創建,Content屬性被設置爲「765」,然後Content屬性被設置爲{Binding Path=Txt, Mode=OneWayToSource}

這是一樣的做這樣的事情:

var b = new MyButton(); 
b.Content = "756"; 
b.Content = new Binding(...); 

您是更換Content財產。

(和技術,最後一行應b.SetBinding(MyButton.ContentProperty, new Binding(...));的值正確綁定,但是我用的是更基本的語法,使之更容易理解這個問題。)

循環中的下一個步驟是數據綁定,因此對Content屬性的綁定進行評估。

既然是OneWayToSource綁定,屬性只更新後,能夠改變的源元素,因爲這是第一次結合正在評估,將其設置爲任何默認是這個DependencyProperty,使他們的源'重新同步。

Button.Content依賴項屬性的情況下,默認值是null,所以你的源元素被設置爲null

因爲DP從綁定中獲取值而不是使用默認值,所以您看不到此行爲與TwoWay綁定。

如果你要設置你的價值的結合已經成立後,如在Loaded事件的按鈕,你會看到你的源屬性正確地得到更新當您設置按鈕的Content

void MyButton_Loaded(object sender, EventArgs e) 
{ 
    ((Button)sender).Content = "756"; 
} 

末後的,如果你想從您的自定義控制設置Content屬性的默認值,則需要覆蓋MetaData該屬性,像這樣:

// Note that this is the static constructor, not the normal one 
static MyButton() 
{ 
    ContentProperty.OverrideMetadata(typeof(MyButton), 
     new FrameworkPropertyMetadata("756")); 
} 

這將使得Content屬性的默認值爲"756"而不是null

+0

+1我刪除了我的答案,因爲它更好,因爲它解釋了爲什麼綁定按照它的方式工作。我也不知道你可以設置一個像這樣的綁定'b.Content = new Binding(...)',並且認爲你必須使用'SetBinding(..)'方法。謝謝你的提示。 – 2013-04-29 19:27:58

+0

@Benjamin Errmmm可能是一個錯誤:)我認爲設置'b.Content = new Binding(...)'將設置Content屬性爲綁定對象,而不是評估它(必須測試是當然)。我剛剛使用了這種語法,因爲它可以讓你更容易理解發生的事情:) – Rachel 2013-04-29 19:42:17

+0

是的,你是對的:)當我測試這個時,我認爲我有它的工作,但我錯了(我的測試是有缺陷的)。 – 2013-04-29 19:57:08