私はほとんどバグであると確信している本当に奇妙な問題があります。別のインスタンスと同期する1つのUserControlインスタンスのUserControlへのバインド
私は3つのUserControl、FolderView、LocalFolderView、RemoteFolderViewを持っています。 LocalFolderViewとRemoteFolderViewはどちらもFolderViewを継承し、それぞれ2つの他のコントロール、LocalExplorerとRemoteExplorerで使用されます。
LocalExplorer/RemoteExplorerには、FolderViewにバインドする文字列のリストがあります。
問題は、LocalExplorer/RemoteExplorerのインスタンスが2つ以上ある場合は、ExplorerViewのFolderViewのListBoxに同じ項目が表示されますが、コントロールの依存関係のプロパティは一見異なります。
コードは実際には長いので、できる限り凝縮しようと思います。現在、問題は私が物事を縛っている方法であると信じています。
LocalExplorer.xaml(RemoteExplorer.xamlが同一のパターンに従う):
<UserControl x:Class="LocalExplorer"
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:local="clr-namespace:MyNamespace"
mc:Ignorable="d"
Width="Auto"
Height="Auto"
ClipToBounds="True"
x:Name="explorer">
<local:ExplorerBase Path="{Binding ElementName=explorer, Path=Path}" Orientation="{Binding ElementName=explorer, Path=Orientation}">
<local:ExplorerBase.FolderView>
<local:LocalFolderView x:Name="FolderView" Path="{Binding Path, RelativeSource={RelativeSource AncestorType={x:Type local:LocalExplorer}}}"/>
</local:ExplorerBase.FolderView>
</local:ExplorerBase>
</UserControl>
LocalExplorer.xaml.cs(RemoteExplorer
は、ここで私はそれの複数のインスタンスは、バグを示していコントロールです。 xaml.cs)は同じパターンに従う:
public partial class Explorer : UserControl
{
#region Explorer
public Explorer()
{
InitializeComponent();
}
#endregion
#region Dependency Properties
public static DependencyProperty PathProperty = DependencyProperty.Register("Path", typeof(string), typeof(Explorer), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public string Path
{
get
{
return (string)GetValue(PathProperty);
}
set
{
SetValue(PathProperty, value);
}
}
#endregion
}
次に、すべての探検に特定のUIロジックを収容ExplorerBase、である。
ExplorerBase.cs:私はそれがテーマ/ Generic.xamlのアプローチを使用してテンプレート
public partial class ExplorerBase : Control
{
public ExplorerBase()
{
this.DefaultStyleKey = typeof(ExplorerBase);
}
public override void OnApplyTemplate()
{
base.ApplyTemplate();
}
public static readonly DependencyProperty FolderViewProperty = DependencyProperty.Register("FolderView", typeof(object), typeof(ExplorerBase), null);
public object FolderView
{
get
{
return GetValue(FolderViewProperty);
}
set
{
SetValue(FolderViewProperty, value);
}
}
public static DependencyProperty PathProperty = DependencyProperty.Register("Path", typeof(string), typeof(ExplorerBase), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public string Path
{
get
{
return (string)GetValue(PathProperty);
}
set
{
SetValue(PathProperty, value);
}
}
}
:
<Style TargetType="{x:Type Imagin.Controls:ExplorerBase}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Imagin.Controls:ExplorerBase">
<ContentPresenter Content="{TemplateBinding FolderView}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
そして最後に、私は信じてFolderViewは、バグを持っているものです。 FolderViewは、使用される実際のコントロールLocalFolderViewとRemoteFolderViewのベースです。このバグは、LocalExplorerとRemoteExplorerの両方を使用するかどうかにかかわらず発生します。私は一度に合計2つのインスタンスだけをテストしました。
FolderView.xaml:
<UserControl x:Class="FolderView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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"
mc:Ignorable="d"
Height="Auto"
Width="Auto"
x:Name="folderView">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisibility" />
<Imagin.Data:InverseBooleanToVisibilityConverter x:Key="InverseBoolToVisibility" />
<Grid>
<ListBox x:Name="ListBox" AllowDrop="True" ItemsSource="{Binding Path=Items, RelativeSource={RelativeSource AncestorType={x:Type local:FolderView}}}" SelectionMode="Extended" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Resources>
<DataTemplate DataType="{x:Type local:BindableFile}">
<local:Thumbnail FilePath="{Binding Path}" IsCheckBoxEnabled="False" ToolTip="{Binding ToolTip}" Title="{Binding Name}" Width="Auto" Height="Auto"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:BindableFolder}">
<local:Thumbnail FilePath="{Binding Path}" IsCheckBoxEnabled="False" ToolTip="{Binding ToolTip}" Title="{Binding Name}" Width="Auto" Height="Auto"/>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<DataGrid x:Name="DataGrid" ItemsSource="{Binding Items, RelativeSource={RelativeSource AncestorType={x:Type local:FolderView}}}" AutoGenerateColumns="False" BorderThickness="0" AlternationCount="2" GridLinesVisibility="None" HeadersVisibility="Column" CanUserAddRows="False" CanUserResizeColumns="True" IsSynchronizedWithCurrentItem="True" AllowDrop="True">
</DataGrid>
</Grid>
</UserControl>
FolderView.xaml.cs:
public abstract partial class FolderView : UserControl
{
#region DependencyProperties
public static DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof(ObservableCollection<BindablePath>), typeof(FolderView), new FrameworkPropertyMetadata(new ObservableCollection<BindablePath>(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public ObservableCollection<BindablePath> Items
{
get
{
return (ObservableCollection<BindablePath>)GetValue(ItemsProperty);
}
set
{
SetValue(ItemsProperty, value);
}
}
public static DependencyProperty PathProperty = DependencyProperty.Register("Path", typeof(string), typeof(FolderView), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnPathChanged));
public string Path
{
get
{
return (string)GetValue(PathProperty);
}
set
{
SetValue(PathProperty, value);
}
}
private static void OnPathChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e)
{
FolderView FolderView = (FolderView)Object;
FolderView.Refresh();
FolderView.SearchTextBox.Text = string.Empty;
}
#endregion
#region Methods
public virtual void GetItems(string Path, out List<string> Folders, out List<string> Files)
{
Folders = default(List<string>);
Files = default(List<string>);
}
/// <summary>
/// Refreshes current path with contents.
/// </summary>
public virtual void Refresh()
{
//Used to debug property values at runtime. So far the values for each object instance are unique.
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(this))
{
string name = descriptor.Name;
object value = descriptor.GetValue(this);
Console.WriteLine("{0}={1}", name, value);
}
}
/// <summary>
/// Populates controls with actual items via binding. We must do this on UI thread. This occurs immediately after <Refresh()>.
/// </summary>
/// <param name="Folders"></param>
/// <param name="Files"></param>
public virtual void Populate(List<FtpListItem> Folders, List<FtpListItem> Files)
{
}
public virtual void Populate(List<string> Folders, List<string> Files)
{
}
#endregion
#region FolderView
public FolderView()
{
InitializeComponent();
}
#endregion
}
LocalFolderView.cs(RemoteFolderView.csは同じパターンに従う):注意すべき
public sealed class LocalFolderView : FolderView
{
public override void GetItems(string Path, out List<string> Folders, out List<string> Files)
{
//These are my own functions
Folders = Directory.GetDirectories(Path);
Files = Directory.GetFiles(Path, null);
}
public override void Populate(List<string> Folders, List<string> Files)
{
int NumFolders = Folders.Count, NumFiles = Files.Count;
this.IsEmpty = NumFolders == 0 && NumFiles == 0 ? true : false;
if (Folders == null || Files == null || (NumFolders == 0 && NumFiles == 0)) return;
for (int j = 0, Count = NumFolders; j < Count; j++)
{
this.Items.Add(new BindableFolder(Folders[j]));
}
for (int j = 0, Count = NumFiles; j < Count; j++)
{
this.Items.Add(new BindableFile(Files[j]));
}
}
public override void Refresh()
{
base.Refresh();
this.Items.Clear();
//If directory doesn't exist, we don't want to enter it.
if (!System.IO.Directory.Exists(this.Path)) return;
List<string> Folders = null;
List<string> Files = null;
string CurrentPath = this.Path;
BackgroundWorker Worker = new BackgroundWorker();
Worker.DoWork += (s, e) =>
{
this.GetItems(CurrentPath, out Folders, out Files);
};
Worker.RunWorkerCompleted += (s, e) =>
{
//Start populating items
var DispatcherOperation = Application.Current.Dispatcher.BeginInvoke(new Action(() => this.Populate(Folders, Files)));
};
Worker.RunWorkerAsync();
}
}
観光:
- 両方のインスタンスのFolderView内のDataGridにも同じ項目が設定されます。
- 各FolderViewインスタンスのパスプロパティが異なります。
- これは、2番目のインスタンスにアイテムを入力した後で、最初のアイテムにアイテムを挿入しようとした場合にのみ発生します。私が最初のインスタンスを最初に移入すると、2番目のインスタンスに何も起こりません。
- 私は両方のインスタンスが同じアイテムで作成されていると言います。つまり、最初のアイテムを作成すると、最初のアイテムが2番目のアイテムに表示されます。そして、もし私が2番目のものを埋めると、2番目のアイテムが最初に現れます。
- また、 "populate"と言うと、私はFolderViewに
Path
プロパティを設定していることを意味します。
物事は私が試してみた:
- 私はバインドする方法を変更します。たとえば、
Binding ElementName=explorer, Path=Property
のようにバインドする代わりに、Binding Property, RelativeSource={RelativeSource AncestorType={x:Type local:UserControlType}}
に変更します。 x:Name
の属性をさまざまな要素から削除します。- FolderViewのプロパティ/値をダンプします。上記のソースの例です。
正直なところ、どのようにデバッグするのか分かりません。これはバグですか、そうではありませんか?
編集
ここ私は2つのエクスプローラインスタンスを表示する方法は次のとおりです。
<local:LocalExplorer />
<local:RemoteExplorer/>
彼らは、私はどちらかが誤って、特にどのように深く考えると、他に特異的に結合することができるかが表示されない、両方の自分自身のインスタンスで考えますリストボックスはビジュアルツリー内にネストされています。
Omg、ありがとうございます。 –