簡體   English   中英

WPF綁定與自定義內容控件上的DataContext

[英]WPF Binding with DataContext on Custom Content Control

我有一個自UserControl派生的自定義向導控件WizardControl ,該UserControl具有一個名為Pages的依賴項屬性,其自定義類集合的數據類型為WizardPageCollection

WizardControl托管在一個帶有稱為MainViewModel的視圖模型的Window ,該向導的頁面使用XAML實例化。

我試圖將頁面綁定到聲明為MainViewModel屬性的子視圖模型Page1VMPage2VM

DataContextPage1VM的第一頁綁定工作正常,但是第二頁的綁定失敗,並顯示以下錯誤消息:

System.Windows.Data Error: 3 : Cannot find element that provides DataContext. BindingExpression:Path=Page2VM; DataItem=null; target element is 'MyPage' (Name=''); target property is 'DataContext' (type 'Object')

問:為什么綁定在第一頁上起作用,但是在第二頁上失敗,有什么辦法可以MainViewModel起作用,同時仍將MainViewModel聲明在MainWindowDataContext XAML標記內? 我不想將ViewModel用作字典資源,因為這會對我們產生一些影響,我將不做詳細介紹。

如評論員所建議,如果我按如下所示更改綁定以使用RelativeSource:

<common:MyPage DataContext="{Binding DataContext.Page1VM, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
<common:MyPage DataContext="{Binding DataContext.Page2VM, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />

第一個綁定可以正常運行,但是第二個綁定仍然失敗,但是帶有不同的錯誤消息(如預期的那樣):

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1''. BindingExpression:Path=DataContext.Page2VM; DataItem=null; target element is 'MyPage' (Name=''); target property is 'DataContext' (type 'Object')

謝謝你的時間!

我的代碼清單如下所示:

MainWindow XAML:

<Window.DataContext>
    <common:MainViewModel />
</Window.DataContext>
<Grid>
    <common:WizardControl>
        <common:WizardControl.Pages>
            <common:WizardPageCollection>
                <common:MyPage DataContext="{Binding Page1VM}" />
                <common:MyPage DataContext="{Binding Page2VM}" />
            </common:WizardPageCollection>
        </common:WizardControl.Pages>
    </common:WizardControl>
</Grid>

MainViewModel和PageViewModel:

public class MainViewModel
{
    public PageViewModel Page1VM
    {
        get;
        set;
    }

    public PageViewModel Page2VM
    {
        get;
        set;
    }

    public MainViewModel()
    {
        this.Page1VM = new PageViewModel("Page 1");
        this.Page2VM = new PageViewModel("Page 2");
    }
}

public class PageViewModel
{
    public string Title { get; set; }
    public PageViewModel(string title) { this.Title = title; }
}

WizardControl XAML:

<Grid>
    <ContentPresenter Grid.Row="0" x:Name="contentPage"/>
</Grid>

WizardControl的代碼背后:

public partial class WizardControl : UserControl
{
    public WizardControl()
    {
        InitializeComponent();
    }

    public WizardPageCollection Pages
    {
        get { return (WizardPageCollection)GetValue(PagesProperty); }
        set { SetValue(PagesProperty, value); }
    }

    public static readonly DependencyProperty PagesProperty =
        DependencyProperty.Register("Pages", typeof(WizardPageCollection), typeof(WizardControl), new PropertyMetadata(new WizardPageCollection(), new PropertyChangedCallback(Pages_Changed)));

    static void Pages_Changed(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        WizardPageCollection col =  e.NewValue as WizardPageCollection;
        WizardControl ctrl = obj as WizardControl;
        ctrl.contentPage.Content = col.First();
    }
}

public class WizardPageCollection : ObservableCollection<WizardPageBase> { }

public class WizardPageBase : ContentControl { }

MyPage XAML:

<Grid>
    <Label Content="{Binding Title}"   />
</Grid>

您的方法取決於Window的DataContext屬性的值繼承 ,該屬性對您的WizardPageCollection不起作用,因為它不會形成WPF元素樹。

您應該改為將MainViewModel創建為資源,然后通過StaticResource進行引用:

<Window ...>
    <Window.Resources>
        <common:MainViewModel x:Key="MainViewModel"/>
    </Window.Resources>
    <Window.DataContext>
        <Binding Source="{StaticResource MainViewModel}"/>
    </Window.DataContext>
    <Grid>
        <common:WizardControl>
            <common:WizardControl.Pages>
                <common:WizardPageCollection>
                    <common:MyPage DataContext="{Binding Page1VM,
                                       Source={StaticResource MainViewModel}}"/>
                    <common:MyPage DataContext="{Binding Page2VM,
                                       Source={StaticResource MainViewModel}}"/>
                </common:WizardPageCollection>
            </common:WizardControl.Pages>
        </common:WizardControl>
    </Grid>
</Window>

@Clemens回答解決問題的方法,但問題是其他的,恕我直言。

  1. 將項目添加到WizardPageCollection時,也應將其添加到LogicalTree。 查看ItemsControl的來源以獲取靈感。 絕對有可能使綁定工作保持原樣。

  2. 我將在這里使用viewmodel first方法。 將頁面定義為頁面視圖模型的集合並生成視圖。 最后,xaml如下所示:

     <common:WizardControl PagesSource="{Binding Pages}"> <common:WizardControl.PageTemplate> <DataTemplate> <common:MyPage DataContext="{Binding }" /> </DataTemplate> </common:WizardControl.PageTemplate> </common:WizardControl> 

或者,考慮您的WizardControl是從Selector類而不是usercontrol派生的。 (選擇器是列表框中的基類。它具有itemssource和選定的項目)。

    <common:WizardControl ItemsSource="{Binding Pages}" 
                          SelectedItem="{Binding SelectedPage}">
        <common:WizardControl.ItemTemplate>
            <DataTemplate>
                <common:MyPage DataContext="{Binding }" />
            </DataTemplate>
        </common:WizardControl.ItemTemplate>
    </common:WizardControl>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM