У меня есть следующий DataTemplate
<DataTemplate x:Key="ArchiveModeContentTemplate">
<Button Style="{x:Static ui:ButtonStyles.DrawingButtonLabel}" Grid.Row="1" Grid.Column="0" Foreground="{x:Static ui:UbiBrushes.UbiDarkBlue}"
Content="{StaticResource ValidateIcon48}" ui:StyleProperties.Label="{DynamicResource Archive}"
Command="{Binding ElementName=factory,Path=BuildPopup}">
<i:Interaction.Behaviors>
<pop:PopupFactory x:Name="factory" Factory="{Binding ConfirmArchivingFactory}" />
</i:Interaction.Behaviors>
</Button>
</DataTemplate>
PopupFactory
имеет команду BuildPopup
. эта Команда дается кнопке с привязкой к ElementName
.
При первом отображении этого шаблона данных он работает нормально. Кнопка получить команду. Но если этот шаблон данных выгружается, а затем отображается снова, привязка дает кнопке команду предыдущего экземпляра PopupFactory
, а не вновь созданного экземпляра.
Перехожу в конструктор PopupFactory
и он привязывается к новой кнопке. Так что это не проблема PopupFactory
совместного использования шаблонами.
Почему это происходит? это ошибка с кешем xaml?
Изменить
Теперь у меня есть еще более странная ошибка.
Я изменил синтаксис на следующий, чтобы иметь привязку elementName после объявления имени в Xaml. Теперь команда работает правильно, но вторая кнопка, которая использует привязку RelativeSource
для поиска команды с именем GoBack
, больше не работает. Я использовал snoop для проверки привязки, и он жалуется, что не может найти команду BuildPopup
????. WPF сходит с ума!
<Button Style="{x:Static ui:ButtonStyles.DrawingButtonLabel}" Grid.Row="1" Grid.Column="0" Foreground="{x:Static ui:UbiBrushes.UbiDarkBlue}"
Content="{StaticResource ValidateIcon48}" ui:StyleProperties.Label="{DynamicResource Archive}">
<i:Interaction.Behaviors>
<pop:PopupFactory x:Name="Archivefactory" Factory="{Binding ConfirmArchivingFactory}" IsSingleInstance="False" />
</i:Interaction.Behaviors>
<Button.Command>
<Binding ElementName="Archivefactory" Path="BuildPopup" />
</Button.Command>
</Button>
<Button Grid.Row="1" Grid.Column="1"
Style="{x:Static ui:ButtonStyles.DrawingButtonLabel}"
Content="{StaticResource CrossIcon48}"
Foreground="Green"
ui:StyleProperties.Label="{DynamicResource Cancel}"
Command="{Binding Path=GoBack, RelativeSource={RelativeSource AncestorType={x:Type ui:DrillDown}}}" />
Изменить
Здесь код PopupFactory
public class PopupFactory : Behavior<UIElement>
{
public ICommand BuildPopup { get; private set; }
private bool _canExecute;
private IDisposable _canexecuteSubscription = null;
public IObservable<bool> CanExecuteSource
{
get { return (IObservable<bool>)GetValue(CanExecuteSourceProperty); }
set { SetValue(CanExecuteSourceProperty, value); }
}
// Using a DependencyProperty as the backing store for CanExecute. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CanExecuteSourceProperty =
DependencyProperty.Register("CanExecute", typeof(IObservable<bool>), typeof(PopupFactory), new PropertyMetadata(null));
private static void OnCanExecuteSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs arg)
{
var factory = obj as PopupFactory;
factory._canexecuteSubscription?.Dispose();
if (arg.NewValue != null)
{
factory._canexecuteSubscription = ((IObservable<bool>)arg.NewValue)
.ObserveOnDispatcher()
.Subscribe(factory.UpdateCanExecute);
}
}
private void UpdateCanExecute(bool value)
{
_canExecute = value;
((RelayCommand<object>)BuildPopup).RaiseCanExecuteChanged();
}
public IFactory Factory
{
get { return (IFactory)GetValue(FactoryProperty); }
set { SetValue(FactoryProperty, value); }
}
// Using a DependencyProperty as the backing store for Factory. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FactoryProperty =
DependencyProperty.Register("Factory", typeof(IFactory), typeof(PopupFactory), new PropertyMetadata(null, OnFactoryChanged));
private static void OnFactoryChanged(DependencyObject obj, DependencyPropertyChangedEventArgs arg)
{
var factory = obj as PopupFactory;
((RelayCommand<object>)factory.BuildPopup).RaiseCanExecuteChanged();
}
public UIElement PlacementTarget
{
get { return (UIElement)GetValue(PlacementTargetProperty); }
set { SetValue(PlacementTargetProperty, value); }
}
// Using a DependencyProperty as the backing store for PlacementTarget. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PlacementTargetProperty =
DependencyProperty.Register("PlacementTarget", typeof(UIElement), typeof(PopupFactory), new PropertyMetadata(null));
public PlacementMode Placement
{
get { return (PlacementMode)GetValue(PlacementProperty); }
set { SetValue(PlacementProperty, value); }
}
// Using a DependencyProperty as the backing store for Placement. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PlacementProperty =
DependencyProperty.Register("Placement", typeof(PlacementMode), typeof(PopupFactory), new PropertyMetadata(PlacementMode.Center));
public bool IsSingleInstance
{
get { return (bool)GetValue(IsSingleInstanceProperty); }
set { SetValue(IsSingleInstanceProperty, value); }
}
// Using a DependencyProperty as the backing store for IsSingleInsance. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsSingleInstanceProperty =
DependencyProperty.Register("IsSingleInstance", typeof(bool), typeof(PopupFactory), new PropertyMetadata(false));
private bool _singleInstanceShowed = false;
public PopupFactory()
{
BuildPopup = new RelayCommand<object>((f) =>
{
ShowPopup(f);
}, (p) =>
{
return _canExecute && Factory != null && !_singleInstanceShowed;
});
UpdateCanExecute(true);
}
public IOverlayContainer ShowPopup(object parameter)
{
var param = new PopupParameter() { Owner = AssociatedObject };
UIElement target = PlacementTarget != null ? PlacementTarget : AssociatedObject;
var item = Factory.Build(parameter);
param.Content = item.Item;
param.Owner = AssociatedObject;
param.RemoveCondition = item.DisposeStream;
var container = OverlayManager.ShowPopup(param);
var placement = new PopupRelativePlacement(container as FrameworkElement, target,
Placement, false);
item.PostFactory?.Invoke();
if (IsSingleInstance)
{
_singleInstanceShowed = true;
OverlayManager.PopupOperations.Where((op) => op.Id == container.Id && op.Operationtype == OverlayOperation.OpType.PopupRemoved)
.Once((_) =>
{
_singleInstanceShowed = false;
((RelayCommand<object>)BuildPopup).RaiseCanExecuteChanged();
});
}
return container;
}
}
IsSingleInstance
не имеет отношения к проблеме. Он только сообщает popupFactory, что он не может генерировать всплывающее окно, если оно уже открыто. Я уберу его из примера кода, чтобы избежать путаницы. - person Gael   schedule 11.09.2019