Hallo zusammen,
ich habe aktuell wieder ein Problem, welches ich nicht nachvollziehen kann. Ich nutze InteractionTriggers auch an anderen Stellen und überall funktioniert es bisher, aber hier nicht:
<DataGridTemplateColumn Header="UserState"
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="UserStateCombobox" ItemsSource="{Binding Source={StaticResource UserStates}}"
Background="{Binding RelativeSource={RelativeSource Self}, Path=SelectedItem, Converter={StaticResource UserStateToColorConverter}}"
SelectedItem="{Binding UserState}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="DropDownClosed">
<i:InvokeCommandAction Command="{Binding UserStateChangedCommand}" CommandParameter="{Binding ElementName=UserStateCombobox, Path=SelectedItem}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Der EventTrigger wird nie ausgelöst, weder wenn ich als EventName DropDownClosed noch SelectionChanged nehme. Im Intellisense wird mir Beim Binding des Commands das UserStateChangedCommand angeboten, daher gehe ich mal davon aus, dass es nicht daran liegt, dass hier auf den falschen DataContext geschaut wird. Ich vermute eher, dass es hier eine Besonderheit gibt wegen dem <DataTemplate>. Bei anderen Spalten funktionieren alle Bindings, aber keine davon ist eine DataGridTemplateColumn.
Würde mich über eine Erklärung durch die Experten freuen.
Nein, das wars leider nicht 🙁
Hallo zusammen,
ich habe ein Problem mit dem ich nicht weiter komme und hoffe es kann mir jemand helfen.
Ich habe ein Datagrid in meinem XAML mit einem EventTrigger + InvokeCommandAction
<i:EventTrigger EventName="ColumnReordered">
<i:InvokeCommandAction
Command="{Binding HistoryColumnsReordered}"
CommandParameter="{Binding Columns, UpdateSourceTrigger=PropertyChanged, ElementName=historyGrid, Converter={StaticResource DatagridColumnsToDisplayIndicesConverter}}" />
</i:EventTrigger>
Mein Problem ist, wenn ich einen Breakpoint in den DatagridColumnsToDisplayIndicesConverter setze, kommt er dort nur genau einmal hin (und tut auch was er soll), anschließend wird das Command auch mit dem korrekten Parameter aufgerufen.
Wenn ich jetzt manuell im Datagrid eine Spalte verschiebe, wird zwar das Command aufgerufen, aber der übergebene Parameter ist derselbe wie beim ersten Aufruf und der Converter wird nicht mehr durchlaufen.
Kann sich darauf jemand einen Reim machen?
Ich würde erwarten, dass der Converter jedes Mal durchlaufen wird. Und ich frage mich auch, wenn er nicht durchlaufen wird, woher bekommt das Command im Viewmodel den alten Parameter-Wert immer wieder?
Hier noch der Code des Converters, auch wenn der vermutlich keine Rolle für das Problem spielt:
public class DatagridColumnsToDisplayIndicesConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Collection<DataGridColumn> columns)
{
List<Tuple<int, string>> columnIndices = columns.Select(column => new Tuple<int, string>(column.DisplayIndex, (string)column.Header)).ToList();
System.Diagnostics.Debug.WriteLine("DatagricColumnsToDisplayIndicesConverter " + string.Join(",", columnIndices.Select(x => x.Item1)));
return columnIndices;
}
throw new ArgumentException("Invalid binding parameters for DatagridColumnsToDisplayIndicesConverter, parameter must be a value of type Collection<DatagridColumn>!");
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new Exception("Invalid call - one way only");
}
}
Danke schonmal
Hallo zusammen,
ich beiße mir gerade die Zähne aus an einem kleinen Problem. Es geht um einen Handshake mit einer SPS, eine Art Heartbeat sozusagen.
Dazu habe ich einen Task der in einer Schleife while(_heartbeatActive) läuft und regelmäßig das entsprechende Bit von der SPS liest. Regelmäßig heißt dabei so viel wie am Ende steht ein await Task.Delay(50) um nicht die CPU komplett auszulasten. Wenn der Wert true ist schicke ich asynchron eine Notification ab. Der Empfänger wartet dann 500ms und setzt den Wert wieder auf false, die SPS schreibt dann nach 500ms Wartezeit den Wert wieder auf true zurück usw.
Jetzt ist es so, dass das Ganze teilweise stundenlang funktioniert und plötzlich "verliere" ich eine Wertänderung, wodurch ich dann keine Notification mehr erzeuge, niemand mehr den Wert umtoggled und das Ganze dann stehen bleibt.
Nachdem ich jetzt ewig versucht habe, das Problem zu finden, hab ich es durch Logging (kann nicht debuggen auf dem Zielsystem) soweit eingrenzen können, dass im Fehlerfall die Zeile await Task.Delay(50) plötzlich 900ms oder länger braucht.
Über irgendeine Idee, wie das sein kann, würde ich mich freuen.
Danke, werd ich mir mal anschauen. Ich habs zwar in der Zwischenzeit bereits mit einem Itemscontrol umgesetzt, das bindet aber an eine Collection mit Usercontrols zur Zeit. Wäre sicher schöner, wenn ich das mit der verlinkten Lösung hinbekäme.
Hallo zusammen,
ich habe ewig kein WPF mehr benutzt und muss jetzt eine Visualisierung basteln, allerdings bin ich ziemlich eingerostet, was WPF angeht.
Ich habe folgendes Problem:
Der Bediener kann zur Laufzeit über ein Hauptmenü (verknüpft im ViewModel über Commands) GruppenControls hinzufügen und entfernen. So weit so gut:
public class MainViewModel
{
//...
private async Task AddNewGroupCommandAction()
{
// Vorab wird über Netzwerk an eine Gegenstelle await ... gemacht
// Dann lege ich mein neuen Gruppen-Usercontrol an und speichere es in einer List
GroupViewModel vm = new GroupViewModel();
GroupUserControl ctrl = new GroupUserControl(vm);
// intern wird NotifyPropertyChanged etc. ausgeführt
AddGroupControlToListProperty(ctrl);
}
//...
}
Da es maximal 8 Gruppen sein können, habe ich im MainView ein 4x2 Grid als Hauptelement. Ich würde jetzt gerne die GroupUserControls per Binding and meine GroupControlList binden, so dass die einzelnen UserControls in jeweils einer Zelle im Grid angezeigt werden, falls vorhanden. Also Element 0 der List in Zelle 1,1 usw.
<Page x:Class="Vendor.Pages.GroupView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Vendor.Pages"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance Type=local:MainViewModel, IsDesignTimeCreatable=True}"
Title="GroupView">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
</Grid>
</Page>
Erste Idee wäre jetzt, jeweils ein ContentControl für jede Zelle einzufügen und dann dessen Content an jeweils einen Eintrag in der List zu binden, aber genau da weiß ich nicht, wie ich an ein bestimmtes Element der Liste binden könnte.
Ist der Ansatz an sich falsch, gibt es einen besseren Weg?
Über einen Schubser in die richtige Richtung würde ich mich freuen.
Danke schonmal.
Hallo zusammen,
ich habe ein borderless Fenster, beim MouseEnter wird die Maus an ein Control innerhalb des Fensters gecaptured, beim MouseLeave soll das Capture gelöst werden.
Das funktioniert auch soweit, es sei denn, man bewegt die Maus schnell, bzw. ruckartig aus dem Fenster raus. Dann wird das MouseLeave Event nicht geworfen.
Ich habe diesen alten Thread hier im Forum gefunden:
MouseLeave Event wird nicht zuverlässig ausgelöst
Dort wird dies als allgemeines Problem beschrieben und vorgeschlagen, einen Timer zu verwenden, der regelmäßig prüft, ob die Maus noch über dem Fenster ist.
Ich habe genau das versucht, und dabei in dem Timer.Tick Handler geprüft, ob die Properties IsMouseOver und IsMouseDirectlyOver noch gesetzt sind.
Zu meiner Überraschung ändern sich aber auch die Werte dieser Properties nicht, wenn die Maus ruckartig aus dem Fenster gezogen wird. IsMouseOver bleibt dann permanent auf true, bis ich einmal außerhalb des Fensters klicke.
Daher meine Frage: Worauf könnte ich im Timer.Tick Handler noch prüfen, um festzustellen, dass die Maus nicht mehr über dem Fenster ist? Muss ich wirklich Mauskoordinaten holen und diese mit der Fensterposition vergleichen? Kann doch eigentlich nicht wahr sein, oder?
Danke schonmal.
Hallo witte,
danke erstmal für die Antwort. Ich habs mal ausprobiert, AllowDrop="True" im popup ändert leider nichts. Auch nicht im ContentControl 😦
Hallo zusammen,
<ComboBox
x:Name="DropdownSelection"
AllowDrop="True"
DragOver="DropdownSelection_DragOver"
DataContext="{Binding ToolBar.ViewModel}"
Style="{StaticResource DropdownMenuStyle}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Image
x:Name="item"
Width="48"
Height="48"
AllowDrop="True"
Drop="item_Drop"
HorizontalAlignment="Center"
Source="{Binding ImgIcon}"
Stretch="Uniform" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Style x:Key="DropdownMenuStyle" TargetType="ComboBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid x:Name="OuterGrid">
<WpfControls:IconToggleButton
x:Name="Expand"
IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
<Popup
Name="Popup"
AllowsTransparency="True"
Focusable="False"
IsOpen="{TemplateBinding IsDropDownOpen}"
Placement="Bottom"
PlacementTarget="{Binding ElementName=OuterGrid}">
<ContentControl
Content="{Binding ViewModel}"
ContentTemplate="{StaticResource LayoutViewModel}"/>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Mein Problem an der Stelle, welches ich mir absolut nicht erklären kann:
DropDownSelection_DragOver -> dieses Event wird ausgelöst, wenn ich ein Objekt über den IconToggleButton ziehe.
Im Handler des Events setze ich IsDropDownOpen der Combobox auf true, d.h. das Popup mit den Images öffnet sich. So weit so gut.
Jetzt würde ich gerne über item_Drop mitbekommen, wenn das gezogene Objekt über einem der Items (Images) gedroppt wird. Das funktioniert aber nicht. Beim Drop über einem Bild wird kein Event ausgelöst.
Hat jemand eine Erklärung dafür?
Danke