Ich arbeite an einem benutzerdefinierten Zahlenauswahlsteuerelement in UWP, und ich versuche, ein Ansichtsmodell an seine SelectedValue-Eigenschaft zu binden. Auch wenn die Bindung in beide Richtungen und der Aktualisierungstrigger auf PropertyChanged
gesetzt sind, funktioniert meine Bindung in keiner Richtung. Momentan habe ich mit Event-Handlern daran gearbeitet, aber ich möchte dieses Steuerelement in eine Bibliothek für benutzerdefinierte Steuerelemente für unser Unternehmen aufteilen und es sofort einsatzbereit machen lassen. Es folgt mein Steuercode und die grundlegenden Code der Seite ich die Kontrolle in bin mit:UWP Benutzerdefinierte Steuerelementbindung funktioniert in keiner Richtung
NumberPicker.xaml:
<ItemsControl
x:Class="UWPApp.Scorekeeper.NumberPicker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UWPApp.Scorekeeper"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vms="using:UWPApp.Scorekeeper.Models.ViewModels"
mc:Ignorable="d"
x:Name="Select"
Loaded="Select_Loaded"
ItemsSource="{x:Bind ItemsCollection}"
d:DesignHeight="300"
d:DesignWidth="400">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="local:NumberItem">
<Viewbox HorizontalAlignment="Stretch" Height="115">
<TextBlock Text="{x:Bind Value}"></TextBlock>
</Viewbox>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Template>
<ControlTemplate>
<Grid BorderThickness="4" BorderBrush="Black">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Rectangle Opacity=".5">
<Rectangle.Fill>
<LinearGradientBrush StartPoint=".5,0" EndPoint=".5,1">
<GradientStop Offset="0" Color="Black"/>
<GradientStop Offset="1" Color="Transparent"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<ScrollViewer Grid.RowSpan="3" ViewChanged="Select_ViewChanged" VerticalSnapPointsType="Mandatory" VerticalSnapPointsAlignment="Center" x:Name="MinutesSelect" HorizontalScrollMode="Disabled" VerticalScrollMode="Auto" VerticalScrollBarVisibility="Visible">
<ItemsPresenter></ItemsPresenter>
</ScrollViewer>
<Rectangle Grid.Row="2" Opacity=".5">
<Rectangle.Fill>
<LinearGradientBrush StartPoint=".5,1" EndPoint=".5,0">
<GradientStop Offset="0" Color="Black"/>
<GradientStop Offset="1" Color="Transparent"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
NumberPicker.xaml.cs:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using UWPApp.Scorekeeper.Models.ViewModels;
using UWPApp.Scorekeeper.Toolbox;
namespace UWPApp.Scorekeeper
{
public class NumberItem
{
public NumberItem(int? value)
{
Value = value;
}
public int? Value { get; set; }
}
public sealed partial class NumberPicker : ItemsControl
{
public event SelectionChangedEventHandler SelectionChanged;
public int RangeBottom { get; set; }
public int RangeTop { get; set; }
public static readonly DependencyProperty SelectedValueProperty = DependencyProperty.Register("SelectedValue", typeof(int?), typeof(NumberPicker), new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedValueChanged)));
public static readonly DependencyProperty SelectionChangedProperty = DependencyProperty.Register("SelectionChanged", typeof(SelectionChangedEventHandler), typeof(NumberPicker), new PropertyMetadata(null));
private static void OnSelectedValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var picker = d as NumberPicker;
picker.SelectionChanged?.Invoke(picker, new SelectionChangedEventArgs(new List<object> { e.OldValue }, new List<object> { e.NewValue }));
return;
}
public int? SelectedValue { get { return (int?)GetValue(SelectedValueProperty); } set { SetValue(SelectedValueProperty, value); } }
public ObservableCollection<NumberItem> ItemsCollection { get; set; }
public NumberPicker()
{
this.InitializeComponent();
DataContext = this;
ItemsCollection = new ObservableCollection<NumberItem>();
}
private void Select_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
if (!e.IsIntermediate)
{
var scroll = sender as ScrollViewer;
var position = scroll.VerticalOffset;
var value = Math.Floor(position/115d);
SelectedValue = ((int)value);
}
}
private void Select_Loaded(object sender, RoutedEventArgs e)
{
var count = RangeTop - RangeBottom + 1;
var items = Enumerable.Range(RangeBottom, count).Select(m => new NumberItem(m)).ToList();
foreach (var item in items)
{
ItemsCollection.Add(item);
}
ItemsCollection.Insert(0, new NumberItem(null));
ItemsCollection.Add(new NumberItem(null));
var period = TimeSpan.FromMilliseconds(10);
Windows.System.Threading.ThreadPoolTimer.CreateTimer(async (source) =>
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal,() =>
{
var scroll = Select.FindFirstChild<ScrollViewer>();
if (SelectedValue != null)
{
var position = SelectedValue * 115d + 81.5;
scroll.ChangeView(null, position, null, true);
}
});
}, period);
}
}
}
Seite. xAML:
<Page
x:Class="UWPApp.Scorekeeper.SelectPenaltyTime"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UWPApp.Scorekeeper"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vms="using:UWPApp.Scorekeeper.Models.ViewModels"
mc:Ignorable="d"
x:Name="PageElement"
Background="{ThemeResource SystemControlBackgroundAccentBrush}"
d:DesignHeight="600"
d:DesignWidth="1024">
<ContentPresenter x:Name="MainContent" Margin="0,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid Background="{ThemeResource SystemControlBackgroundAccentBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="110*"/>
<RowDefinition Height="43*"/>
<RowDefinition Height="47*"/>
</Grid.RowDefinitions>
<local:NumberPicker Margin="100,0,750,0" RangeBottom="0" RangeTop="20" SelectedValue="{Binding ElementName=PageElement,Path=ViewModel.Minutes,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></local:NumberPicker>
</Grid>
</ContentPresenter>
</Page>
Page.xaml.cs:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using UWPApp.Scorekeeper.Models.TransportClasses;
using UWPApp.Scorekeeper.Models.ViewModels;
namespace UWPApp.Scorekeeper
{
public sealed partial class SelectPenaltyTime : Page
{
public GameStateModel StateModel { get; set; }
public AddPenalty_FVM ViewModel { get; set; }
public SelectPenaltyTime()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var message = e.Parameter as PenaltyMessage;
StateModel = message.StateModel;
ViewModel = message.ViewModel;
}
private void NumberPicker_Loaded(object sender, RoutedEventArgs e)
{
var picker = sender as NumberPicker;
picker.SelectedValue = ViewModel.Minutes;
}
private void NumberPicker_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var picker = sender as NumberPicker;
ViewModel.Minutes = picker.SelectedValue;
}
}
}
AddPenalty_FVM:
public class AddPenalty_FVM
{
public int? Minutes { get; set; }
}
Wo ist Ihr ViewModel, implementiert es INotifyProperty-Schnittstelle? – RTDev
Es sollte nicht nötig sein, oder? Da der Wert nur geladen wird, wenn die Seite geladen wird?Das heißt, nur der Selektor setzt die Viewmodel-Eigenschaft. – Ceshion
Es scheint, dass dies alles eine Einschränkung von 'Binding' ist, da es korrekt mit' x: Bind' funktioniert. – Ceshion