1
votes

I have one UsersControl.xaml

<UserControl x:Name="userControl" x:Class="Lloyd.Shared.Controls.UsersControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:Interactivity="http://schemas.microsoft.com/expression/2010/interactivity"
         xmlns:Behaviors="clr-namespace:Lloyd.Shared.Controls.Behaviors"
         xmlns:local="clr-namespace:Lloyd.Shared.Controls"
         mc:Ignorable="d" DataContext="{Binding Mode=OneWay, RelativeSource={RelativeSource Self}}"
         d:DesignHeight="300" d:DesignWidth="300">

<Interactivity:Interaction.Behaviors>
    <Behaviors:ImportUsersOnLoadedBehavior />
</Interactivity:Interaction.Behaviors>
<DockPanel LastChildFill="True">
    <Label Content="账号" DockPanel.Dock="Top" FontSize="18.667" />

    <StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" HorizontalAlignment="Right">
        <Button x:Name="AddAccountButton" Height="26" Width="80" Content="添加" Margin="5" Command="{Binding AddUserCommand}" />
        <Button x:Name="ImportAccountsButton" Height="26" Width="80" Content="导入" Margin="5" Command="{Binding ImportUsersCommand}"/>
        <Button x:Name="DeleteAccountButton" Height="26" Width="80" Content="删除" Margin="5" Command="{Binding RemoveUsersCommand}"/>
    </StackPanel>

    <ListView x:Name="accountListbox" Margin="5" BorderThickness="1" BorderBrush="{DynamicResource AccentColorBrush}" ItemsSource="{Binding UsersCollection}"/>
</DockPanel>

Code behind

public partial class UsersControl : UserControl
{
    public static ObservableCollection<User> GetUsersCollection(DependencyObject obj)
    {
        return (ObservableCollection<User>)obj.GetValue(UsersCollectionProperty);
    }

    public static void SetUsersCollection(DependencyObject obj, ObservableCollection<User> value)
    {
        obj.SetValue(UsersCollectionProperty, value);
    }

    // Using a DependencyProperty as the backing store for UsersCollection.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty UsersCollectionProperty =
        DependencyProperty.RegisterAttached("UsersCollection", typeof(ObservableCollection<User>), typeof(UsersControl), new FrameworkPropertyMetadata(null,FrameworkPropertyMetadataOptions.AffectsRender));


}

and i use this UsersControl in my MainWindow.xaml and bind the UsersCollection to main windows's DataContext.

<Controls:MetroWindow x:Class="ZggwwDocuments.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:c="clr-namespace:Lloyd.Shared.Controls;assembly=Lloyd.Shared.Controls"
    xmlns:vm="clr-namespace:ZggwwDocuments.ViewModels"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:ZggwwDocuments"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="697.514">
<Controls:MetroWindow.DataContext>
    <vm:MainWindowViewModel/>
</Controls:MetroWindow.DataContext>
<Grid Margin="5">
    <c:UsersControl UsersCollection="{Binding Users}"  />
</Grid>

I set breakpoints on MainWindow and it's DataContext and Users Property is not null. But the binding between MainWindow.DataContext.Users and UsersControl.UsersCollection failed. The following is from the Output window

System.Windows.Data Error: 40 : BindingExpression path error: 'Users' property not found on 'object' ''UsersControl' (Name='userControl')'. BindingExpression:Path=Users; DataItem='UsersControl' (Name='userControl'); target element is 'UsersControl' (Name='userControl'); target property is 'UsersCollection' (type 'ObservableCollection`1')

GetUsersCollection(DependencyObject obj) in UsersControl.xaml.cs always return null

2

2 Answers

1
votes

Try

ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type c:UsersControl}}, Path=UsersCollection}"

OR, you can be clever and take;

<DockPanel LastChildFill="True">
    <Label Content="账号" DockPanel.Dock="Top" FontSize="18.667" />

    <StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" HorizontalAlignment="Right">
        <Button x:Name="AddAccountButton" Height="26" Width="80" Content="添加" Margin="5" Command="{Binding AddUserCommand}" />
        <Button x:Name="ImportAccountsButton" Height="26" Width="80" Content="导入" Margin="5" Command="{Binding ImportUsersCommand}"/>
        <Button x:Name="DeleteAccountButton" Height="26" Width="80" Content="删除" Margin="5" Command="{Binding RemoveUsersCommand}"/>
    </StackPanel>

    <ListView x:Name="accountListbox" Margin="5" BorderThickness="1" BorderBrush="{DynamicResource AccentColorBrush}" ItemsSource="{Binding UsersCollection}"/>
</DockPanel>

... and shove it inside;

<UserControl.Template>
   <ControlTemplate TargetType="{x:Type UserControl}">
      (paste it here)
   </ControlTemplate>
</UserControl.Template>

Then change the binding to;

{Binding RelativeSource={RelativeSource TemplatedParent}, Path=UsersCollection}

Personally I'd recommend this method as opposed to the first as the binding is quicker, less prone to ... 'issues'... and it also means you're overwriting the template of the user control to be what you actually want it to be rather than just dumping some XAML inside its existing template.

0
votes

Try to call your attached property like bellow:

<c:UsersControl UsersControl.UsersCollection="{Binding Users}"  />