我很简单(我希望:))问题:
在MVVM中,View通常会侦听ViewModel属性的更改.但是,我有时会喜欢听事件,例如,当VM发出信号时,View可以启动动画或关闭窗口.
通过带有NotifyPropertyChanged的bool属性(并且只有当它从false变为true时才开始动画)可以做到这一点,但感觉就像是一个hack,我更喜欢暴露事件,因为它在语义上是正确的.
此外,我想在代码隐藏中没有代码的情况下这样做,因为这样做viewModel.myEvent += handler意味着我已经手动取消注册事件以允许View为GC'd - WPF视图已经能够弱地监听属性',而且我更喜欢在View中以声明方式编程.
标准的强事件订阅也很糟糕,因为我需要为一个View切换多个ViewModel(因为每次创建View需要占用太多的CPU时间).
感谢您的想法(如果有标准的解决方案,msdn的链接就足够了)!
我正在编写一个WPF控件,它是Button的子类.然后我在Themes\generic.xaml中提供了一个默认样式,它看起来像这样(简化):
<Style TargetType="{x:Type WPFControls:MyButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type WPFControls:MyButton}">
<Button
x:Name="PART_Button"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Run Code Online (Sandbox Code Playgroud)
我希望用户有机会更改控件的背景,但如果他没有,我想提供默认值.我该怎么做?
当我在发布的代码中执行它时,Background和BorderBrush为null(=不存在),除非用户明确指定它们(这有效地强制用户总是提供一些值),但标准的Windows控件(如Button)提供了默认的外观,仍然可以由用户定制.如何在我的控制下做到这一点?
谢谢!
Michael Morton解决方案:
您可以在样式中提供默认设置:
<Style TargetType="{x:Type TestTemplate:MyButton}">
<Setter Property="Background" Value="Red" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TestTemplate:MyButton}">
<Button
x:Name="PART_Button"
IsEnabled="{TemplateBinding IsEnabled}"
Content="{TemplateBinding Content}"
Background="{TemplateBinding Background}"
/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Run Code Online (Sandbox Code Playgroud)
用法:
<StackPanel>
<TestTemplate:MyButton Background="Blue">Explicitly blue</TestTemplate:MyButton>
<TestTemplate:MyButton>Naturally red</TestTemplate:MyButton>
</StackPanel>
Run Code Online (Sandbox Code Playgroud) 我正在开发LOB应用程序,我将需要多个对话框窗口(并且在一个窗口中显示所有内容不是一个选项/没有意义).
我希望我的窗口有一个用户控件来定义一些样式等,并且可以有几个插入内容的插槽 - 例如,模态对话框窗口的模板将有一个内容插槽和按钮(这样用户就可以提供带有绑定ICommands的内容和按钮组.
我想有这样的东西(但这不起作用):
UserControl xaml:
<UserControl x:Class="TkMVVMContainersSample.Services.Common.GUI.DialogControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
>
<DockPanel>
<DockPanel
LastChildFill="False"
HorizontalAlignment="Stretch"
DockPanel.Dock="Bottom">
<ContentPresenter ContentSource="{Binding Buttons}"/>
</DockPanel>
<Border
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
Padding="8"
>
<ContentPresenter ContentSource="{Binding Controls}"/>
</Border>
</DockPanel>
</UserControl>
Run Code Online (Sandbox Code Playgroud)
这样的事情可能吗?我怎么告诉VS我的控件暴露了两个内容占位符,以便我可以像这样使用它?
<Window ... DataContext="MyViewModel">
<gui:DialogControl>
<gui:DialogControl.Controls>
<!-- My dialog content - grid with textboxes etc...
inherits the Window's DC - DialogControl just passes it through -->
</gui:DialogControl.Controls>
<gui:DialogControl.Buttons>
<!-- My dialog's buttons with wiring, like
<Button Command="{Binding HelpCommand}">Help</Button>
<Button Command="{Binding CancelCommand}">Cancel</Button>
<Button …Run Code Online (Sandbox Code Playgroud) 我有一组表示菜单项的对象(viewmodels).当单击MenuItem时,每个命令都要执行.
如果我想静态地进行菜单,我这样做:
<ContextMenu>
<MenuItem Header="{Binding Text1}" Command={Binding Command1}>
<MenuItem Header="{Binding Text2}" Command={Binding Command2}>
</ContextMenu>
Run Code Online (Sandbox Code Playgroud)
但是当我事先不知道这些项目(它们来自集合)时,我需要分配ContextMenu.ItemsSource - 并将文本放入ItemTemplate.
<ContextMenu ItemsSource="{Binding MyMenuItems}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text2}" /> <!-- But where to put Command binding? TextBlock.Command makes no sense, and we have no access to MenuItem! -->
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
Run Code Online (Sandbox Code Playgroud)
但是,这样,我无法将Command绑定到 - 因为我无法获取每一行的MenuItem!
请问有什么建议吗?感谢你们!
作为我的应用程序的根视图,我有一个ZStack,我想添加两个浮动栏,一个位于视口的底部,一个位于视口的顶部。
使用单个栏很容易(ZStack(alignment: .top)),但是有没有一种方法可以添加多个后代,并使一个与顶部对齐,另一个与底部对齐?
我尝试alignment从 ZStack 中删除,并将.frame(alignment: .top)/添加.frame(alignment: .bottom)到子级中,但这没有任何作用。
是的,可以通过将顶部对齐的 ZStack 与另一个底部对齐的 ZStack 包装起来来破解,但这看起来相当不优雅。
我在C#中编写VSTO Outlook插件,我需要区分,无论是MailItem是传入还是传出(或者两者都不是,例如它是草稿).
有一些万无一失的方法吗?我现在的最佳解决方案是获取收件人,cc和bcc的列表,从活动帐户加载电子邮件地址,并检查这两个列表是否相交,但这对我来说似乎非常脆弱,我希望有更好的解决方案.
使用案例:我想获得一封电子邮件的相关日期,可能是ReceivedTime或SentOn,但要知道我应该使用哪一个,我想知道邮件是发送还是收到.
谢谢你的想法:)
我想知道C#Invoke函数是如何工作的(我现在正在考虑从工作线程调用一个从GUI线程调用GUI的方法):
假设我有两个线程,每个线程都有它的指针指针,指向当前执行的指令.
现在,我在工作线程中调用Invoke来在GUI线程中运行委托.当GUI线程已经拥有它的指令指针(IP),并且每个线程只能有一个时,这怎么可能?当我突然调用我的代码时,该IP会发生什么?那么如何使GUI线程继续处理它正在做的事情(它的以前的IP以某种方式恢复)?
这个问题的概括是,当我想从线程1调用函数f()时,如何在一些其他线程的上下文中执行f()...
谢谢你的启发:)!
我已经为Button创建了自己的ControlTemplate,如下所示:
<Style x:Key="LightButtonStyle" TargetType="{x:Type ButtonBase}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<Border
x:Name="WrappingBorder"
Margin="{TemplateBinding Margin}"
...
>
<ContentPresenter
Content="{TemplateBinding Content}"
...
>
</ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Run Code Online (Sandbox Code Playgroud)
现在,我注意到当我将余量设置为我的按钮时,例如:
<Button
Style="{StaticResource LightButtonStyle}"
Margin="20"
>
Hello world!
</Button>
Run Code Online (Sandbox Code Playgroud)
按钮实际上是双边距-40.我认为控件实际上应该从不使用边距,并且在安排阶段只有按钮的祖先才能读取边距属性.我已经看了WPF的默认样式,并发现没有人使用过Margin.
这是正确的结论(保证金只能由集装箱正确安排)吗?换句话说,每次我在我的风格中使用{TemplateBinding Margin}时,我会获得双倍边距?是否有一些类似属性的列表,我的控件不应该使用(因为它们仅仅用于"周围世界")?
你能指点我的MSDN页面来解释这个吗?谢谢!
编辑:
我想我应该在http://msdn.microsoft.com/en-us/library/ms745058.aspx和http://msdn.microsoft.com/en-us/library/ms751709.aspx找到答案,但我不知道我们认为他们明确提到使用Margin属性永远不是控制者,它始终是评估它并使用它来影响布局的祖先或wpf系统......
我正在编写一个侦听网络连接的应用程序,当某些数据到达时,它会回复,并且根据传入的数据,它可能需要在回复之前询问用户(显示对话框).
我不知道如何在MV-VM架构中干净地完成这项工作:如果我只需要根据传入的数据更新GUI,事件和对可观察集合的绑定就很好,但是如果我在回复之前确实需要来自用户的anwer怎么办? ?
更糟糕的是,我希望同步这样做,因为我希望我的回复算法位于一个地方,而不是分成多个回调,并且不清楚"谁叫谁调用谁"的责任.
简单地说,像
HandleMessage(Message msg){
string reply;
if (msg.type == 1) {
reply = ...
} else {
string question = msg...
reply = ShowModalDialog(question); // MVVM violation!
}
sender.Send(reply);
}
Run Code Online (Sandbox Code Playgroud)
但是我不想从模型中调用view或viewmodel,因为模型需要可重用和可测试 - 我不希望在每次测试运行时都弹出对话框,这将违反MVVM!没有事件(据我所知,它们只是单向的,并且没有向后通道来获取对事件源的回复)或数据绑定,因为它将是异步的.
这可行吗?这是一个我问过几个测试驱动的开发传播者的问题,到目前为止,我没有得到实际可用的答案.然而,在处理过程中需要一些额外的输入是相当普遍的.
谢谢!
编辑:这是应用程序逻辑,所以它显然属于模型,即使在这种情况下它没有,我想知道在模型中业务逻辑例程中我真正需要用户输入的情况的解决方案.
我的View中有一个ItemsControl,它绑定到ViewModel的ObservableCollection.该集合已被填充,之后将引发从VM到视图的事件(想想搜索结果和SearchFinished事件).
我想将键盘焦点移动到ItemsControl中的第一个项目,但是当我在处理SearchFinished时在View的代码隐藏中执行它时,项目尚未呈现(集合已经填充,但是wpf的呈现是异步的并且没有'发生了),所以没有什么可以聚焦(Focus()需要已经构建了项目的可视树).
我想(myItemsControl.ItemContainerGenerator.ContainerFromIndex(0)作为UIElement).Focus();,但是由于第0项尚未加载,ContainerFromIndex(0)返回null.
我尝试用Dispatcher.BeginInvoke延迟它...优先级低,但这取决于确切的时间,通常不起作用.
我怎么能等到ItemsControl中的第一项加载?