C# 点击新项目时折叠Xamarin ListView中的所有项目
我有一个看似相对简单的问题,但我无法解决 我有一个Xamarin ListView,它使用ViewCells的项目模板,如下所示:C# 点击新项目时折叠Xamarin ListView中的所有项目,c#,xaml,listview,xamarin,xamarin.forms,C#,Xaml,Listview,Xamarin,Xamarin.forms,我有一个看似相对简单的问题,但我无法解决 我有一个Xamarin ListView,它使用ViewCells的项目模板,如下所示: <ListView HasUnevenRows="True" ItemsSource="{Binding Devices}" ItemTemplate="{StaticResource DeviceDataTemplateSelector}"
<ListView HasUnevenRows="True"
ItemsSource="{Binding Devices}"
ItemTemplate="{StaticResource DeviceDataTemplateSelector}"
SelectionMode="None"
ItemTapped="NewItemTapped"
/>
目前,“DeviceDataTemplateSelector”始终返回以下ViewCell(稍后将添加更多ViewCell)
ViewCell使用Xamarin社区工具包中的Expander控件
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
xmlns:ViewModel="clr-namespace:App.ViewModels"
x:Class="App.UI.ViewCellStandardTemplate">
<ViewCell.View>
<!-- Calls an expander for each ViewCell. -->
<xct:Expander HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Margin="{StaticResource UniversalMargin}"
>
<xct:Expander.Header>
<Grid HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Margin="{StaticResource UniversalMargin}">
<Grid.RowDefinitions>
<RowDefinition Height = "*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width = "*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="Header Text" />
</Grid>
</xct:Expander.Header>
<xct:Expander.Content>
<Grid HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Margin="{StaticResource UniversalMargin}">
<Grid.RowDefinitions>
<RowDefinition Height = "*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width = "*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0"
Grid.Column="0"
Text="Click Me"
Command="{Binding Source={RelativeSource AncestorType={x:Type ViewModel:PageViewModel}, Mode=FindAncestorBindingContext}, Path=ClickCommand}"
CommandParameter="{Binding .}"
/>
</Grid>
</xct:Expander.Content>
</xct:Expander>
</ViewCell.View>
</ViewCell>
到目前为止,所有这些都正常工作-问题是,当我点击ListView中的某个项目时,我希望任何其他展开的项目都折叠起来
换句话说,当我点击ViewCell展开它时,我希望ListView中的所有其他ViewCell将其各自的Expander控件的“IsExpanded”属性设置为false
我尝试在ListView中调用“ItemTapped”事件,然后在ListView中的元素之间循环-我不确定这是否是正确的方法
在ViewCell中访问Expander控件属性的最佳方式是什么
我不知道该怎么做——任何帮助都将不胜感激
谢谢。已更新 编辑以提供纯UI解决方案,灵感来自(或可以尝试此) 两个步骤:
ViewCell
和ListView
TapCommand
我在ViewModel中通过在Expander的stacklayout上使用命令解决了这个问题: 在Xaml中,以两个扩展器为例: xct:Expander.Header xct:Expander.Header> 在ViewModel中: //变量声明 专用扩展器_openExpander=新扩展器() 公共命令onexpandertapedcommand{get;set;} //在构造函数中 OnExpanderTappedCommand=新命令((o)=>OnExpanderTappedCommandExecute(o)) //命令执行方法
private void OnExpanderTappedCommandExecute(object o)
{
Expander currentExpanderClicked = (Expander)o;
if (currentExpanderClicked.IsExpanded)
{
_openExpander.IsExpanded = false;
_openExpander = currentExpanderClicked;
_openExpander.IsExpanded = true;
}
}
也许对调查此事的人有用。我的灵感来自于原始帖子的广泛逻辑。当你“循环浏览列表视图中的元素”时会发生什么?您是否成功地将“IsExpanded”属性设置为false?但它实际上并没有使它们崩溃?这可能是个好主意,也可能不是个好主意。IsExpanded在模型域中可能没有任何意义;它可能只是视图状态的一部分。(仅供参考:这是数据绑定的一个更大问题的一部分;它在从模型进行简单映射方面很好,但在视图需要更复杂时就不太好了。因此,要么执行与将视图与模型分离的目标背道而驰的操作,要么需要“视图模型”每一个项目,这是笨拙的/容易出错的,因为现在有两个继承人需要保持同步。我怀疑数据绑定最终会被放弃。可能是MVU,但我还没有研究。)我同意只在大多数情况下保留逻辑(例外情况如列表需要根据数据扩展某些项目)并在未接触ViewModel的情况下更新了解决方案。不幸的是,由于各种原因,我无法使用此解决方案。我需要数据模板选择器来选择不同的视图单元格。更重要的是,我也希望尽可能多地保留MVVM。在模型中有一个扩展状态将打破这一局面。我尝试了第一种方法,但无法使其正常工作,因为将ViewCell.View强制转换为stackpanel总是会引发空异常-不确定原因。我本以为会有一个相对简单的方法来实现这一点,它遵循MVVM,但显然不是:/但是我非常感谢答案的努力!糟糕的是,我还在ViewCell上测试Tapped事件,并在那里添加了StackLayout并对逻辑进行编码。只需
var child=cell。将视图视为扩展器就可以了,还更新了答案。嗨@DR_Bart,您是否尝试过更新的代码(更改了一行)。
private void Expander_Tapped(object sender, EventArgs e)
{
var expander = sender as Expander;
var state = expander.IsExpanded;
var cells = MyList.GetType().GetRuntimeProperties()
.FirstOrDefault(info => info.Name == "TemplatedItems")?.GetValue(MyList);
if (cells != null) {
foreach (ViewCell cell in cells as ITemplatedItemsList<Cell>)
{
if (cell.BindingContext != null)
{
var child = cell.View as Expander;
child.IsExpanded = false;
}
}
}
expander.IsExpanded = state;
}
public class YourDeviceModel : INotifyPropertyChanged
{
private bool flag;
public bool Flag
{
get => flag;
set
{
flag = value;
OnPropertyChanged("Flag");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
public ICommand TapCommand => new Command<YourDeviceModel>(OnItemTapped);
private void OnItemTapped(YourDeviceModel currentSelection)
{
//if your Devices is a ObservableCollection, convert it and reset all flags
Devices.ToList().ForEach(x => x.Flag = false);
//set the current one to true
currentSelection.Flag = true;
}
<xct:Expander
IsExpanded="{Binding Flag, Mode=TwoWay}"
Command="{Binding Source={RelativeSource AncestorType={x:Type ViewModel:PageViewModel}, Mode=FindAncestorBindingContext}, Path=TapCommand}"
CommandParameter="{Binding .}">
private void OnExpanderTappedCommandExecute(object o)
{
Expander currentExpanderClicked = (Expander)o;
if (currentExpanderClicked.IsExpanded)
{
_openExpander.IsExpanded = false;
_openExpander = currentExpanderClicked;
_openExpander.IsExpanded = true;
}
}