use*_*952 0 c# xaml caliburn.micro windows-phone-8
所以我正在开发一个带有Caliburn.Micro框架的Windows Phone 8应用程序.我正在尝试创建一个网格,我在运行时在运行时添加/删除TextBlock等元素.我已经尝试了一些东西来将我的代码绑定到x:Name但到目前为止还没有任何工作.
所以我尝试过的一件事就是在我的xaml aka视图中有一个占位符网格:
<Grid x:Name="ContentPanel" Margin="0,97,0,0" Grid.RowSpan="2">
</Grid>
Run Code Online (Sandbox Code Playgroud)
然后我的ViewModel使用以下内容绑定我的ContentPanel网格:
private Grid contentPanel;
public Grid ContentPanel
{
get
{
return contentPanel;
}
set
{
contentPanel = value;
NotifyOfPropertyChange(() => ContentPanel);
}
}
Run Code Online (Sandbox Code Playgroud)
然后我创建了一个TextBlock来添加到网格中:
TextBlock txt1 = new TextBlock();
txt1.Text = "2005 Products Shipped";
txt1.FontSize = 20;
txt1.FontWeight = FontWeights.Bold;
Grid.SetRow(txt1, 1);
Run Code Online (Sandbox Code Playgroud)
最后我将TextBlock添加到我的网格:
ContentPanel.Children.Add(txt1);
Run Code Online (Sandbox Code Playgroud)
当我运行此代码ContentPanel时,结果是等于null,为什么呢?不应该Caliburn自动绑定ContentPanel x:Name="ContentPanel"与属性ContentPanel?
我很感激你在这件事上的帮助.
我需要解决的核心问题是: 我在我的应用程序中有一个登录页面,其中显示了从服务器加载的一些图片和文本.如下所示,这是通过Image和TextBlock完成的.当该服务器处于脱机状态或者未启用wi-fi时,我想用静态图像替换此图片+文本.Aka我想从StackPanel中删除TextBlock.
我加载并显示我的服务器的东西的部分很好,在我的xaml中看起来像这样:
<StackPanel Orientation="Horizontal" Background="White" DataContext="{Binding FeedItemsAnnounce,Mode=TwoWay}" >
<Image delay:LowProfileImageLoader.UriSource="{Binding ImagePath,Mode=TwoWay}" Margin="5" Width="170" Height="138">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Tap">
<cm:ActionMessage
MethodName="LoadAnnouncement">
<cm:Parameter Value="{Binding Link}"></cm:Parameter>
</cm:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
<TextBlock Text="{Binding Title}" TextWrapping="Wrap" Width="160" Foreground="Black" FontSize="24" VerticalAlignment="Center" Margin="25,0,0,0"></TextBlock>
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Tap">
<cm:ActionMessage
MethodName="LoadAnnouncement">
<cm:Parameter Value="{Binding Link}"></cm:Parameter>
</cm:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
Run Code Online (Sandbox Code Playgroud)
所以当服务器离线/ wifi禁用时,我想用它替换它.这样TextBlock就不再存在了:
<Image delay:LowProfileImageLoader.UriSource="{Binding ImagePath,Mode=TwoWay}" DataContext="{Binding FeedItemsAdvertisement,Mode=TwoWay}" Margin="0,20,0,39" Width="380" Height="128">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Tap">
<cm:ActionMessage
MethodName="LoadAdvertisement" >
<cm:Parameter Value="{Binding Link}"></cm:Parameter>
</cm:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
Run Code Online (Sandbox Code Playgroud)
这甚至可能吗?如果不是最好的半解决方案是什么?
编辑1:我已按照接受的答案中的说明设置了流程.但我BooleanToVisibilityConverter没有被召唤,尽管我NotifyOfPropertyChange(() => IsConnectionAvailable);被召唤了.
我的财产:
private bool _isConnectionAvailable;
public bool IsConnectionAvailable
{
get { return _isConnectionAvailable; }
set
{
if (_isConnectionAvailable != value)
{
_isConnectionAvailable = value;
NotifyOfPropertyChange(() => IsConnectionAvailable);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我如何更改bool:这个代码在我的构造函数中为我的ViewModel调用(就像测试它是否正常工作):
IsConnectionAvailable = false;
Run Code Online (Sandbox Code Playgroud)
TextBlock(没有触发器代码导致它与之前相同):
<TextBlock Text="{Binding Title}" Visibility="{Binding IsConnectionAvailable, Converter={StaticResource BoolToVisibility}}" TextWrapping="Wrap" Width="160" Foreground="Black" FontSize="24" VerticalAlignment="Center" Margin="25,0,0,0"></TextBlock>
Run Code Online (Sandbox Code Playgroud)
这就像是Binding IsConnectionAvailable无法工作,因为我可以将IsConnectionAvailable我的Xaml中的名称更改为任何内容,我NotifyOfPropertyChange(() => IsConnectionAvailable);仍然会被调用.
有任何想法吗?
我甚Visibility="{Binding Path=IsVisibil,Mode=TwoWay}至无法正常绑定public Visibility IsVisibil属性.我在其他课上做过这个,但即使这样也行不通?
编辑2:绑定不起作用的问题,似乎在这段代码中的某处:
<StackPanel Orientation="Horizontal" Background="White" DataContext="{Binding FeedItemsAnnounce,Mode=TwoWay}" >
<Image delay:LowProfileImageLoader.UriSource="{Binding ImagePath,Mode=TwoWay}" Margin="5" Width="170" Height="138">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Tap">
<cm:ActionMessage
MethodName="LoadAnnouncement">
<cm:Parameter Value="{Binding Link}"></cm:Parameter>
</cm:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
<TextBlock Text="{Binding Title}" Visibility="{Binding Path=IsVisibil,Mode=TwoWay}" TextWrapping="Wrap" Width="160" Foreground="Black" FontSize="24" VerticalAlignment="Center" Margin="25,0,0,0"></TextBlock>
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Tap">
<cm:ActionMessage
MethodName="LoadAnnouncement">
<cm:Parameter Value="{Binding Link}"></cm:Parameter>
</cm:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)
EDIT 1和2的解决方案:我在xaml结构的顶部创建了一个x:Name"Root".然后将绑定更改为:
ElementName=Root, Path=DataContext.IsVisibil
Run Code Online (Sandbox Code Playgroud)
这是必需的,因为我尝试设置的可见性绑定在另一个DataContxt中.
这不是使用CM的正确方法,在许多方面您会混淆CM中的模型和视图模型以及绑定功能.
你目前在做什么
您正在尝试让CM框架查找ContentPanel在ViewModel上调用的属性,并自动确定Grid要将其绑定到的属性...
由于以下几个原因,这不起作用:
CM和绑定
当您使用元素名称绑定(例如x:Name使用CM)时,它会尝试在ViewModel上找到与元素名称匹配的属性.此时,根据所讨论的源控件的约定设置,CM将尝试自动连接所有的零碎.
有一些默认约定,ConventionManager其中确定在使用元素名称绑定时要绑定TextBlock的Text属性- 例如,for上的属性TextBlock绑定到ViewModel上的target属性.
http://caliburnmicro.codeplex.com/SourceControl/latest#src/Caliburn.Micro.Platform/ConventionManager.cs - 查看ConventionManager上的类构造函数,以查看开箱即用的约定 - 没有一个用于Grid
找到目标属性后,CM会将其绑定.
(顺便说一下:值得注意的是,如果控件类型是一个ContentControlCM会做一些组合魔术,所以你可以拥有包含其他视图模型的视图模型,并且在运行时都有一个组合 - 非常适合具有多个子窗口的屏幕等)
您遇到的问题是没有Grid开箱即用的常规设置- 这很可能是因为GridSL/WPF中的主要用于布局,并且实际上不是"数据容器"或以任何方式识别数据(分开)从您可以绑定的少数依赖属性) - 即我不认为可以绑定到网格并获得动态数量的列/行而无需对控件进行一些自定义,因此省略了任何约定
(考虑一下 - 如果你将网格绑定到一个集合,网格应该做什么...添加行或列?它不能以合理的方式支持它)
现在将它带回SL/WPF一秒钟:
通常,如果您需要项目的变量列表,则需要绑定到ItemsSource从ItemsControl(或ItemsControl自身)继承的控件的属性.
许多控件执行此操作:如果他们需要显示动态数量的项目,他们通常会继承ItemsControl.
这与CM有什么关系?
Caliburn Micro知道如何ItemsControl开箱即用.这意味着您可以在ViewModel上包含一个包含项集合的属性,并在绑定后在运行时获得这些属性的动态视图
例如 - CM绑定ItemsControl可能如下所示:
<ItemsControl x:Name="TextItems">
<!-- host the items generated by this ItemsControl in a grid -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- render each bound item using a TextBlock-->
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding SomeTextualProperty}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Run Code Online (Sandbox Code Playgroud)
现在你只需要一个对象集合来绑定它 - 集合中的每个项目都成为控件中的一个新项目,它DataContext指向绑定项目.我假设你希望每个项目都是一个包含属性的ViewModel SomeTextualProperty- 我在这里定义了......
// Provides a viewmodel for a textual item
public class TextItemViewModel
{
public string SomeTextualProperty { get; set;}
}
Run Code Online (Sandbox Code Playgroud)
应包含项列表的VM需要具有要绑定的集合.
(注意:由于您在运行时向其添加项目,因此您需要在集合更改时告知UI - ObservableCollection在实现集合更改通知事件时免费提供此功能)
// This is the viewmodel that contains the list of text items
public class ScreenViewModel
{
public ObservableCollection<TextItemViewModel> TextItems { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
还有什么我会考虑不正确的方法
您的ViewModel不应该知道您的View实现,即他们不应该引用任何类型的控件,除非绝对必要(我不能想到我必须将控件放在VM中的时间).ViewModels应该对视图进行建模 - 但是他们不应该真正需要知道该视图包含的任何细节 - 这样它们更容易测试并且很容易被重用
如果您遵循上述方法,您可以提供一个重用视图模型的应用程序,但为每个视图模型提供不同的视图.您可以通过替换ItemsControl视图中的其他类型的控件来尝试此操作(只要它具有数据感知功能,例如数据网格),并且VM仍然可以工作 - VM是视图无关的.
您Grid在VM中的使用并不理想,因为它Grid是一种可视化控件,它不是数据.请记住,视觉效果是您的View,ViewModel应该只包含数据和事件,通知视图发生的事情
如果我这样做 - 代码看起来更像我上面发布的代码.
总结一下
TextItemViewModel)中显示的信息建模ScreenViewModel使用更改感知集合(例如,)将这些对象的集合添加到主ViewModel()ObservableCollectionItemsControl使用视图x:Name绑定在你的收藏ScreenViewModelItemsControl将观察这些事件并相应地更新自己附录
你可以使用a ObservableCollection<string>而不是a来逃避TextBlockViewModel但是不清楚你是否想要为绑定到网格的项添加更多属性(例如IsHeading标题的属性,然后你可以在视图中使用粗体/斜体)
如果你只是想使用strings只是修改DataTemplate直接绑定到DataContext而不是一个属性DataContext
<ItemsControl x:Name="TextItems">
<!-- host the items generated by this ItemsControl in a grid -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- render each bound item using a TextBlock-->
<ItemsControl.ItemTemplate>
<DataTemplate>
**<TextBlock Text="{Binding}"/> <!-- Bind direct -->**
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Run Code Online (Sandbox Code Playgroud)
编辑:
在你的情况下,它非常简单 - 你的ViewModel应该只是模拟服务器的状态:
public class LoginPageViewModel
{
public bool IsConnectionAvailable { get; set; } // or whatever your variable should be called
}
Run Code Online (Sandbox Code Playgroud)
然后使用转换器将文本块的可见性绑定到此:
<TextBlock Visibility="{Binding IsConnectionAvailable, Converter={StaticResource BooleanToVisibilityConverter}}">
Run Code Online (Sandbox Code Playgroud)
您需要在某处声明转换器的静态资源(例如在控件本身或主资源字典中)
看起来在System.Windows.Controls某个地方已经定义了一个转换器,但是如果你找不到它,那么实现就非常简单了(你可能做得更好一点,以防止无效输入,但为了简洁,我保持它很小) :
public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool) value ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter,CultureInfo culture)
{
throw new NotImplementedException();
}
}
Run Code Online (Sandbox Code Playgroud)
您可能还希望在视图生命周期中将状态从可用/不可用更改,因此在这种情况下,您可能希望使用内置的属性更改事件PropertyChangedBase(Screen也继承)以使视图知道属性何时更改
private bool _isConnectionAvailable;
public bool IsConnectionAvailable
{
get { return _isConnectionAvailable; }
set
{
if (_isConnectionAvailable != value)
{
_isConnectionAvailable = value;
NotifyOfPropertyChange(() => IsConnectionAvailable);
}
}
}
Run Code Online (Sandbox Code Playgroud)
附录2
我更喜欢简洁的CM语法,而不是在绑定动作消息时显式 - 所以你的XAML会改变:
<Image delay:LowProfileImageLoader.UriSource="{Binding ImagePath,Mode=TwoWay}" DataContext="{Binding FeedItemsAdvertisement,Mode=TwoWay}" Margin="0,20,0,39" Width="380" Height="128">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="Tap">
<cm:ActionMessage
MethodName="LoadAdvertisement" >
<cm:Parameter Value="{Binding Link}"></cm:Parameter>
</cm:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
Run Code Online (Sandbox Code Playgroud)
至
<Image delay:LowProfileImageLoader.UriSource="{Binding ImagePath,Mode=TwoWay}" DataContext="{Binding FeedItemsAdvertisement,Mode=TwoWay}" Margin="0,20,0,39" Width="380" Height="128" cal:Message.Attach="[Tap] = [LoadAdvertisement($dataContext.Link)]"></Image>
Run Code Online (Sandbox Code Playgroud)
(实际上,这可能与$ dataContext.Link部分不对......但是它可能会再次......请参阅:http://caliburnmicro.codeplex.com/wikipage?title = All%20About%20Actions&referringTitle=Documentation )
| 归档时间: |
|
| 查看次数: |
1265 次 |
| 最近记录: |