【发布时间】:2020-11-19 10:25:55
【问题描述】:
在 GroceryListViewModel 中有一个名为 ButtonClicked 的命令,我想要一个按钮来使用它。但是,该按钮位于 ListView 的 ViewCell 中,无法访问该命令。我目前正在做的事情会导致每次加载 ViewCell 以及单击 ViewCell 时都会调用该命令。有问题的按钮对列表顶部的一些 ViewCell 不起作用,但在列表的下方起作用。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:VM="clr-namespace:FoodLifeApp.ViewModels"
mc:Ignorable="d"
x:Class="FoodLifeApp.PageViews.GroceryListPage"
x:Name="GroceryList">
<ContentPage.BindingContext >
<VM:GroceryListViewModel x:Name="VMGroceryList"/>
</ContentPage.BindingContext>
<ListView x:Name="MyListView"
ItemsSource="{Binding DisplayList}"
IsGroupingEnabled="True"
HasUnevenRows="True"
CachingStrategy="RecycleElement">
<ListView.Header >
<SearchBar Placeholder="Search"
Text="{Binding SearchText}"
HeightRequest="40"
SearchCommand="{Binding Search}"
/>
</ListView.Header>
<ListView.GroupHeaderTemplate >
<DataTemplate>
<ViewCell Height="20">
<Label Text="{Binding Heading}"
BackgroundColor="LightGray"
FontAttributes="Bold"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Height="40">
<StackLayout Orientation="Horizontal" >
<Label Text="{Binding ProductName}"
VerticalTextAlignment="Center"/>
<Label Text="{Binding ProductSize}"
FontSize="10"
VerticalTextAlignment="Center"/>
<Button ImageSource="{Binding ButtonImage}"
BackgroundColor="Transparent"
CommandParameter="{Binding ProductName}"
Command="{Binding Path=ButtonClicked, Source={x:Reference VMGroceryList}}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
class GroceryListViewModel : ContentPage, INotifyPropertyChanged
{
private List<ShoppingList> _ListOfShoppingList;
private List<ShoppingList> _SearchResults;
private String _searchText;
private Command searchCommand;
public event PropertyChangedEventHandler PropertyChanged;
public GroceryListViewModel()
{
var meatList = new ShoppingList()
{
new ShoppingItem() { ProductName="Beef", ProductQuantity=7},
new ShoppingItem() { ProductName="Chicken", ProductQuantity=3},
new ShoppingItem() { ProductName="Pork", ProductQuantity=5},
};
meatList.Heading = "Meats";
var fruitList = new ShoppingList()
{
new ShoppingItem() { ProductName="Apples", ProductQuantity=12},
new ShoppingItem() { ProductName="Bananas", ProductQuantity=6},
new ShoppingItem() { ProductName="Peaches", ProductQuantity=4},
};
fruitList.Heading = "Fruits";
var vegetableList = new ShoppingList()
{
new ShoppingItem() { ProductName="Corn", ProductQuantity=8},
new ShoppingItem() { ProductName="Potatoes", ProductQuantity=9},
new ShoppingItem() { ProductName="Green Beans", ProductQuantity=8},
new ShoppingItem() { ProductName="Broccoli", ProductQuantity=1}
};
vegetableList.Heading = "Vegetables";
DisplayList = new List<ShoppingList>()
{
meatList,
fruitList,
vegetableList
};
Search = new Command(async () =>
{
ShoppingList tempList = new ShoppingList();
tempList.Heading = "Search Results";
RestHelper restH = new RestHelper();
JObject sRes = await restH.GetKroger(SearchText);
foreach (var currItem in sRes["data"])
{
tempList.Add(new ShoppingItem() { ProductName = currItem["description"].ToString(), ProductQuantity = 0, ProductSize = currItem["items"][0]["size"].ToString()});
}
DisplayList = new List<ShoppingList>() { tempList };
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DisplayList"));
});
}
public List<ShoppingList> DisplayList
{
get
{
if (IsSearchingBool.IsSearchingInstance.getIsSearching())
{
Debug.WriteLine("RETURNING SEARCH RESULTS");
return _SearchResults;
} else
{
Debug.WriteLine("RETURNING GROCERY LIST");
return _ListOfShoppingList;
}
}
set
{
if (IsSearchingBool.IsSearchingInstance.getIsSearching())
{
_SearchResults = value;
} else
{
_ListOfShoppingList = value;
}
base.OnPropertyChanged();
}
}
public String SearchText
{
set
{
if (value.Length == 0 && IsSearchingBool.IsSearchingInstance.getIsSearching() == true)
{
IsSearchingBool.IsSearchingInstance.setIsSearching(false);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DisplayList"));
} else if (value.Length > 0 && IsSearchingBool.IsSearchingInstance.getIsSearching() == false)
{
IsSearchingBool.IsSearchingInstance.setIsSearching(true);
Search.CanExecute(this);
}
_searchText = value;
base.OnPropertyChanged();
}
get
{
return _searchText;
}
}
public ICommand Search
{
get; private set;
}
public ICommand ButtonClicked
{
get
{
Debug.WriteLine("in button clicked");
if (IsSearchingBool.IsSearchingInstance.getIsSearching())
{
Debug.WriteLine("is searching");
return new Command<String>((itemName) => {
Debug.WriteLine(itemName);
Debug.WriteLine(_SearchResults[0].ToString());
Debug.WriteLine(_ListOfShoppingList[0].ToString());
ShoppingItem temp = _SearchResults[0].Find(x => x.ProductName.Equals(itemName));
_SearchResults[0].Remove(temp);
_ListOfShoppingList[0].Add(temp);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DisplayList"));
});
} else
{
Debug.WriteLine("Not searching");
return new Command(() => { });
}
}
}
}
【问题讨论】:
-
请贴出
GroceryListViewModel的相关位 -
我认为
ButtonClicked的定义和绑定是正确的,但是您在实际命令之外做了很多事情,这让您不这么认为。 -
可以使用Relative bindings绑定命令。 viewmodel 可以设置为 BindingContext。
-
@Jason 似乎绑定正确,可能只是我的其余代码不好。您是否碰巧知道为什么在加载列表时会多次调用该命令,或者为什么单击视图单元上的任意位置都可以调用该命令?
-
为什么加载的时候会调用“几次”这个命令?
ButtonClickedget 可能会在每个 Cell 创建时被调用多次,但这并不意味着命令本身正在执行。获取中的 Writeline 和 if 语句不是命令本身的一部分
标签: c# mvvm xamarin.forms binding