我有一个应用程序和一个类库。 我正在使用ninject绑定所有视图模型和Syncfusion作为第三方扩展。
主应用程序显示一个包含正弦波和三角波的RibbonGallery。 选择波浪时,用户可以看到波浪属性的变化。
两个波的几个属性是相同的(频率,振幅和偏移),所以我使用一个usercontrol基类来仅一次实现这些分量。
类库包含用户控件基类名称的实现 StandardView。
每个wave都显示StandardView及其自己的属性(阶段)。
在主应用中选择波浪时,可见性将根据选择进行设置。
在TextBox中写入输入时,ComboBox会自动弹出,用户可以从中选择。
我的问题是,如果用户将输入写入正弦波,则他将选择更改为三角波,然后再次返回正弦波-他将无法从ComboBox中选择任何项-就像这些项被冻结。
我怀疑ComboBox弹出窗口正确,然后是前面的ComboBox弹出窗口,这导致用户无法选择任何项目。
任何帮助将不胜感激。
编辑:(向问题中添加了源代码)
课程库: StandardView(仅适用于频率)
<StackPanel Orientation="Horizontal">
<!--Standard Frequency-->
<Label Content="Frequency" Width="120" Margin="2" VerticalAlignment="Center"></Label>
<syncfusion:DoubleTextBox Name="StandardFrequency" Width="140" Margin="2" Padding="1"
TextWrapping="NoWrap" Focusable="True"
EnterToMoveNext="True" AcceptsReturn="False"
IsReadOnly="{Binding ElementName=readonly, Path=IsChecked}"
Value="{Binding FrequencyValue, Source={x:Static local:ViewModelLocator.StandardViewModel}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
NumberDecimalDigits="8"
HorizontalAlignment="Center" VerticalAlignment="Center" TextAlignment="Center"
VerticalContentAlignment="Center" HorizontalContentAlignment="Center"
ContextMenu="{x:Null}" >
<syncfusion:DoubleTextBox.InputBindings>
<KeyBinding Command="{Binding Path=ApplyValue}" Key="Enter" />
</syncfusion:DoubleTextBox.InputBindings>
</syncfusion:DoubleTextBox>
<ComboBox Name="StandardFrequencyVariable" Width="70" Margin="2" Padding="1"
ItemsSource="{Binding FrequencyValues, Source={x:Static local:ViewModelLocator.StandardViewModel}}" DisplayMemberPath="Key" SelectedValuePath="Key"
SelectedValue="{Binding FrequencyNodeCategory, Source={x:Static local:ViewModelLocator.StandardViewModel}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsDropDownOpen="{Binding IsFrequencyDropDownOpen, Source={x:Static local:ViewModelLocator.StandardViewModel}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsHitTestVisible="False" >
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem" >
<Setter Property="Focusable" Value="False"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</StackPanel>
StandardViewModel:
public class StandardViewModel : INotifyPropertyChanged
{
public StandardViewModel()
{
}
#region Public Properties
private double frequencyValue;
public double FrequencyValue
{
get
{
return frequencyValue;
}
set
{
if( value != frequencyValue )
{
frequencyValue = value;
OnPropertyRaised( "FrequencyValue" );
IsFrequencyDropDownOpen = true;
}
}
}
private string frequencyNodeCategory;
public string FrequencyNodeCategory
{
get
{
return frequencyNodeCategory;
}
set
{
if( value != frequencyNodeCategory )
{
frequencyNodeCategory = value;
OnPropertyRaised( "FrequencyNodeCategory" );
IsFrequencyDropDownOpen = false;
}
}
}
private bool isFrequencyDropDownOpen;
public bool IsFrequencyDropDownOpen
{
get
{
return isFrequencyDropDownOpen;
}
set
{
if( value != isFrequencyDropDownOpen )
{
isFrequencyDropDownOpen = value;
OnPropertyRaised( "IsFrequencyDropDownOpen" );
if( isFrequencyDropDownOpen )
return;
}
}
}
public Dictionary<string, int> FrequencyValues
{
get
{
return frequencyValues;
}
set
{
frequencyValues = value;
}
}
public Dictionary<string, int> frequencyValues = new Dictionary<string, int>(){
{"µHz", -6},
{"mHz", -3},
{"Hz", 0},
{"KHz", 3},
{"MHz", 6},
{"GHz", 9}
};
#endregion
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyRaised( string propertyName = null )
{
PropertyChangedEventHandler handler = PropertyChanged;
if( handler != null )
handler( this, new PropertyChangedEventArgs( propertyName ) );
}
}
SineView:(TriangleView基本相同)
<StackPanel Orientation="Vertical">
<local:StandardView />
<StackPanel Orientation="Horizontal">
<!--Phase-->
<Label Content="Phase" Width="120" Margin="2" VerticalAlignment="Center" ></Label>
<syncfusion:DoubleTextBox Name="StandardSinePhase" Width="140" Margin="2" Padding="1"
TextWrapping="NoWrap" Focusable="True"
EnterToMoveNext="True" AcceptsReturn="False"
IsReadOnly="{Binding ElementName=readonly, Path=IsChecked}"
Value="{Binding StandardSinePhaseValue, Source={x:Static local:ViewModelLocator.SineViewModel}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
NumberDecimalDigits="1"
HorizontalAlignment="Center" VerticalAlignment="Center" TextAlignment="Center"
VerticalContentAlignment="Center" HorizontalContentAlignment="Center"
ContextMenu="{x:Null}" >
<syncfusion:DoubleTextBox.InputBindings>
<KeyBinding Command="{Binding Path=ApplyValue}" Key="Enter" />
</syncfusion:DoubleTextBox.InputBindings>
</syncfusion:DoubleTextBox>
<Label Name="PhaseDegLabel" Content="Deg." Margin="2" Height="30" VerticalAlignment="Center" HorizontalAlignment="Left" HorizontalContentAlignment="Left" VerticalContentAlignment="Center" ></Label>
</StackPanel>
</StackPanel>
SineViewModel:
public class SineViewModel : INotifyPropertyChanged
{
public SineViewModel()
{
}
private double standardSinePhaseValue;
public double StandardSinePhaseValue
{
get
{
return standardSinePhaseValue;
}
set
{
if( value != standardSinePhaseValue )
{
standardSinePhaseValue = value;
OnPropertyRaised( "StandardSinePhaseValue" );
}
}
}
private bool isSineChecked = true;
public bool IsSineChecked
{
get
{
return isSineChecked;
}
set
{
if( value != isSineChecked )
{
isSineChecked = value;
OnPropertyRaised( "IsSineChecked" );
if( isSineChecked == true )
{
}
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyRaised( string propertyName = null )
{
PropertyChangedEventHandler handler = PropertyChanged;
if( handler != null )
handler( this, new PropertyChangedEventArgs( propertyName ) );
}
}
BooleanToVisibilityConverter:
public class BooleanToVisibilityConverter : IValueConverter
{
private bool triggerValue = false;
public bool TriggerValue
{
get
{
return triggerValue;
}
set
{
triggerValue = value;
}
}
private bool isHidden;
public bool IsHidden
{
get
{
return isHidden;
}
set
{
isHidden = value;
}
}
private object GetVisibility( object value )
{
if( !( value is bool ) )
return DependencyProperty.UnsetValue;
bool objValue = ( bool )value;
if( ( objValue && TriggerValue && IsHidden ) || ( !objValue && !TriggerValue && IsHidden ) )
{
return Visibility.Hidden;
}
if( ( objValue && TriggerValue && !IsHidden ) || ( !objValue && !TriggerValue && !IsHidden ) )
{
return Visibility.Collapsed;
}
return Visibility.Visible;
}
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
{
return GetVisibility( value );
}
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
{
if( ( Visibility )value == Visibility.Visible )
{
return true;
}
else
{
return false;
}
}
}
IoC:
public static class IoC
{
#region Public Properties
/// <summary>
/// The kernel for the IoC container
/// </summary>
public static IKernel Kernel { get; private set; } = new StandardKernel();
#endregion
#region Construction
/// <summary>
/// Setups the IoC container, binds all information required
/// </summary>
public static void Setup()
{
// Bind all required view models
BindViewModels();
}
/// <summary>
/// Binds all singleton view models.
/// </summary>
private static void BindViewModels()
{
// Bind to a single instance of application view model
Kernel.Bind<CanvasViewModel>().ToConstant( new CanvasViewModel() );
Kernel.Bind<SineViewModel>().ToConstant( new SineViewModel() );
Kernel.Bind<TriangleViewModel>().ToConstant( new TriangleViewModel() );
Kernel.Bind<StandardViewModel>().ToConstant( new StandardViewModel() );
}
#endregion
/// <summary>
/// Gets a service from the IoC, of the specified type
/// </summary>
/// <typeparam name="T"> the type to get</typeparam>
/// <returns></returns>
internal static T Get<T>()
{
return Kernel.Get<T>();
}
}
ViewModelLocator:
public class ViewModelLocator
{
public static ViewModelLocator Instance { get; private set; } = new ViewModelLocator();
public static CanvasViewModel CanvasViewModel => IoC.Get<CanvasViewModel>();
public static SineViewModel SineViewModel => IoC.Get<SineViewModel>();
public static TriangleViewModel TriangleViewModel => IoC.Get<TriangleViewModel>();
public static StandardViewModel StandardViewModel => IoC.Get<StandardViewModel>();
}
应用
App.xaml.cs:
public partial class App : Application
{
protected override void OnStartup( StartupEventArgs e )
{
// Setup IoC
IoC.Setup();
// Show the main window
Current.MainWindow = new MainWindow();
Current.MainWindow.Show();
}
}
MainWindow:
<Grid>
<local:CanvasView />
</Grid>
CanvasView:
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.Resources>
<!--Hides control if boolean value is true-->
<core:BooleanToVisibilityConverter x:Key="HiddenIfTrue" TriggerValue="True" IsHidden="True"/>
<!--Hides control if boolean value is false-->
<core:BooleanToVisibilityConverter x:Key="HiddenIfFalse" TriggerValue="False" IsHidden="True"/>
<!--Collapses control if boolean value is true InvBoolToVis-->
<core:BooleanToVisibilityConverter x:Key="CollapsedIfTrue" TriggerValue="True" IsHidden="False"/>
<!--Collapses control if boolean value is false BoolToVis-->
<core:BooleanToVisibilityConverter x:Key="CollapsedIfFalse" TriggerValue="False" IsHidden="False"/>
</Grid.Resources>
<syncfusion:RibbonBar Grid.Row="0" Header="Waves" IsLauncherButtonVisible="False" >
<syncfusion:RibbonGallery Name="Standard" ItemWidth="90" ExpandWidth="0" MenuIconBarEnabled="True" VisualMode="InRibbon" >
<syncfusion:RibbonGalleryItem Name="Sine" Content="Sine"
Command="{Binding Path=SineCommand, Source={x:Static core:ViewModelLocator.CanvasViewModel}}"
IsChecked="{Binding Path=IsSineChecked, Source={x:Static core:ViewModelLocator.SineViewModel}, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
<syncfusion:RibbonGalleryItem Name="Triangle" Content="Triangle"
Command="{Binding Path=TriangleCommand, Source={x:Static core:ViewModelLocator.CanvasViewModel}}"
IsChecked="{Binding Path=IsTriangleChecked, Source={x:Static core:ViewModelLocator.TriangleViewModel}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</syncfusion:RibbonGallery>
</syncfusion:RibbonBar>
<StackPanel Grid.Row="1" Margin="0,0,10,0" >
<syncfusion:GroupBar Name="ParametersPanel" AllowDragandDrop="False" HorizontalAlignment="Left" Margin="2" MinWidth="350" ItemHeaderHeight="30" VisualMode="MultipleExpansion" AnimationSpeed="0" >
<!--Group Bar Item-->
<syncfusion:GroupBarItem x:Name="StandardParameters" HeaderText="{Binding StandardParametersCaption, Source={x:Static core:ViewModelLocator.CanvasViewModel}}"
ShowInGroupBar="True" IsExpanded="True" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<core:SineView Grid.Row="0" Visibility="{Binding Path=IsSineChecked,
Source={x:Static core:ViewModelLocator.SineViewModel},
Converter={StaticResource CollapsedIfFalse},UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
<core:TriangleView Grid.Row="0" Visibility="{Binding Path=IsTriangleChecked,
Source={x:Static core:ViewModelLocator.TriangleViewModel},
Converter={StaticResource CollapsedIfFalse},UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
</Grid>
</syncfusion:GroupBarItem>
</syncfusion:GroupBar>
</StackPanel>
</Grid>
答案 0 :(得分:0)
嗨,我在github上上传了示例。请验证。 WPF Sample 1.从标准VM派生三角形VM和正弦VM。因为它们都应该使用一些通用功能。 2.将dataContext TriangleView设置为TriangleVM,对于正弦VM设置相同 3.调整绑定。