|
Apologies for the shouting but this is important.
When answering a question please:
- Read the question carefully
- Understand that English isn't everyone's first language so be lenient of bad spelling and grammar
- If a question is poorly phrased then either ask for clarification, ignore it, or mark it down. Insults are not welcome
- If the question is inappropriate then click the 'vote to remove message' button
Insults, slap-downs and sarcasm aren't welcome. Let's work to help developers, not make them feel stupid.
cheers,
Chris Maunder
The Code Project Co-founder
Microsoft C++ MVP
|
|
|
|
|
For those new to message boards please try to follow a few simple rules when posting your question.- Choose the correct forum for your message. Posting a VB.NET question in the C++ forum will end in tears.
- Be specific! Don't ask "can someone send me the code to create an application that does 'X'. Pinpoint exactly what it is you need help with.
- Keep the subject line brief, but descriptive. eg "File Serialization problem"
- Keep the question as brief as possible. If you have to include code, include the smallest snippet of code you can.
- Be careful when including code that you haven't made a typo. Typing mistakes can become the focal point instead of the actual question you asked.
- Do not remove or empty a message if others have replied. Keep the thread intact and available for others to search and read. If your problem was answered then edit your message and add "[Solved]" to the subject line of the original post, and cast an approval vote to the one or several answers that really helped you.
- If you are posting source code with your question, place it inside <pre></pre> tags. We advise you also check the "Encode "<" (and other HTML) characters when pasting" checkbox before pasting anything inside the PRE block, and make sure "Use HTML in this post" check box is checked.
- Be courteous and DON'T SHOUT. Everyone here helps because they enjoy helping others, not because it's their job.
- Please do not post links to your question into an unrelated forum such as the lounge. It will be deleted. Likewise, do not post the same question in more than one forum.
- Do not be abusive, offensive, inappropriate or harass anyone on the boards. Doing so will get you kicked off and banned. Play nice.
- If you have a school or university assignment, assume that your teacher or lecturer is also reading these forums.
- No advertising or soliciting.
- We reserve the right to move your posts to a more appropriate forum or to delete anything deemed inappropriate or illegal.
cheers,
Chris Maunder
The Code Project Co-founder
Microsoft C++ MVP
|
|
|
|
|
I'm using DevExpress reporting. I'm looking for alternatives.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Is there a reason you need an alternative? If there's a missing feature, that could help people with providing you with suggestions.
|
|
|
|
|
I use a "designer" almost never. You spend 90% of the time getting the last 10% to look / work right (if ever). Writing custom reports isn't that hard if that's what you did before "designers".
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
Using WPF .Core 6
I am trying to create this custom control[^]. I'm open to a better way if anyone has one.
There is the outer Navigation Container, with Navigation Panes inside it. There can be any number of Navigation Panes. Each Navigation Pane will contain Navigation Items as links that the user can click on.
What I would like to happen when the Window shows is for the container to be there, and all the panes added and showing a spinning indicator that is visible as long as the pane is loading. Each pane must load independant of the other, and each could take any amount of time to load.
So far, the Navigation Container displays, and each NavigationPane shows, and the code begind for the Navigation Pane is receiving its data, but nothing shows up. And, the Spinning Indicator never goes away. The problem seems to be in the NavigationPane. The NavigationContainer is working as expected
Here's what I'm getting right now.[^]
I'm NOT getting any binding errors, and all relevant code is being hit - I just don't see anything.
Here's the NavigationContainer's Load() method. It adds each pane first, then retrieves the data for each. This all runs, and the data is assigned to the Items DP on the NavigationPane
private async Task Load()
{
if (NavigationPanes != null)
{
foreach (var navigationPaneModel in NavigationPanes)
{
var pane = new NavigationPane
{
Header = navigationPaneModel.Header ?? "",
NavigationItemType = navigationPaneModel.NavigationItemType
};
ContainerItems.Add(pane);
}
if (_apiProxy != null)
{
foreach (var navigationPaneModel in NavigationPanes)
{
await Task.Run(() =>
{
return _apiProxy.GetNavigationItems(navigationPaneModel.NavigationItemType);
}).ContinueWith(task =>
{
App.Current.Dispatcher.BeginInvoke(() =>
{
var container = ContainerItems.FirstOrDefault(x => x.NavigationItemType == navigationPaneModel.NavigationItemType);
if (container != null && task.Result != null)
{
container.Items = new ObservableCollection<NavigationEntity>(task.Result);
}
});
});
}
}
}
Here's the NavigationPane control from the Generic.xaml file
<Style TargetType="{x:Type ctrls:NavigationPane}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Expander Header="{Binding Header, RelativeSource={RelativeSource TemplatedParent}}"
IsExpanded="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"
Padding="{Binding Padding, RelativeSource={RelativeSource TemplatedParent}}"
Margin="{Binding Margin, RelativeSource={RelativeSource TemplatedParent}}"
BorderBrush="{Binding BorderBrush, RelativeSource={RelativeSource TemplatedParent}}"
BorderThickness="{Binding BorderThickness, RelativeSource={RelativeSource TemplatedParent}}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<Grid>
<ListBox ItemsSource="{Binding Items, RelativeSource={RelativeSource TemplatedParent}}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Margin="2"
BorderBrush="Transparent"
BorderThickness="0">
<ListBox.ItemTemplate>
<DataTemplate>
<mctrls:MaroisHyperlink x:Name="link"
LinkText="{Binding Caption}"
HorizontalAlignment="Left"
Margin="2">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LinkClicked">
<i:InvokeCommandAction Command="{Binding ItemLinkClickedCommand,
RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ctrls:NavigationPane}}}"
CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</mctrls:MaroisHyperlink>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<mctrls:MaroisSpinningProgress HorizontalAlignment="Center"
VerticalAlignment="Center"
BorderThickness="1"
Margin="5,5,5,5"
Visibility="{Binding IsBusyVisible, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
</Expander>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here's the NavigationPane.cs
public class NavigationPane : _ControlBase
{
#region Properties
public NavigationItemType NavigationItemType { get; set; }
private Visibility _IsBusyVisible = Visibility.Visible;
public Visibility IsBusyVisible
{
get { return _IsBusyVisible; }
set
{
if (_IsBusyVisible != value)
{
_IsBusyVisible = value;
RaisePropertyChanged(nameof(IsBusyVisible));
}
}
}
#endregion
#region DP's
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header",
typeof(string),
typeof(NavigationPane),
new PropertyMetadata(""));
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
#endregion
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register("Items",
typeof(ObservableCollection<NavigationEntity>),
typeof(NavigationPane),
new PropertyMetadata(null, new PropertyChangedCallback(OnItemsChanged)));
public ObservableCollection<NavigationEntity> Items
{
get { return (ObservableCollection<NavigationEntity>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
private static void OnItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (NavigationPane)d;
control.IsBusyVisible = Visibility.Collapsed;
}
#endregion
#region CTOR
public NavigationPane()
{
}
static NavigationPane()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NavigationPane),
new FrameworkPropertyMetadata(typeof(NavigationPane)));
}
#endregion
}
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
My immediate thought is that the problem is in the task continuation. Have you checked the result of the FirstOrDefault, to make sure that it is actually finding the container?
|
|
|
|
|
Kevin Marois wrote: Each pane must load independant of the other
That doesn't seem to tally with:
Kevin Marois wrote:
foreach (var navigationPaneModel in NavigationPanes)
{
await Task.Run(() =>
{
return _apiProxy.GetNavigationItems(navigationPaneModel.NavigationItemType);
}).ContinueWith(task =>
{
App.Current.Dispatcher.BeginInvoke(() =>
{
var container = ContainerItems.FirstOrDefault(x => x.NavigationItemType == navigationPaneModel.NavigationItemType);
if (container != null && task.Result != null)
{
container.Items = new ObservableCollection<NavigationEntity>(task.Result);
}
});
});
} Your loop kicks off a task to load each pane, then waits for that task to complete before trying to load the next pane.
Try extracting the "load a pane" code to a separate method:
private async Task LoadPane(NavigationPane navigationPaneModel)
{
var result = await Task.Run(() => _apiProxy.GetNavigationItems(navigationPaneModel.NavigationItemType);
if (result is null) return;
var container = ContainerItems.FirstOrDefault(x => x.NavigationItemType == navigationPaneModel.NavigationItemType);
if (container is null) return;
container.Items = new ObservableCollection<NavigationEntity>(result);
} Then change the loop to:
List<Task> tasks = new List<Task>(NavigationPanes.Count);
foreach (var navigationPaneModel in NavigationPanes)
{
tasks.Add(LoadPane(navigationPaneModel));
}
await Task.WhenAll(tasks);
Kevin Marois wrote:
control.IsBusyVisible = Visibility.Collapsed; You've declared the IsBusyVisible property as a regular property, but your NavigationPane class is a DependencyObject . The WPF binding system will only observe changes to DependencyProperty properties on a DependencyObject -derived class. Change the property to a dependency property:
public static readonly DependencyProperty IsBusyVisibleProperty = DependencyProperty.Register(
"IsBusyVisible", typeof(Visibility), typeof(NavigationPane),
new PropertyMetadata(Visibility.Visible));
public Visibility IsBusyVisible
{
get { return (Visibility)GetValue(IsBusyVisibleProperty); }
set { SetValue(IsBusyVisibleProperty, value); }
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks. This make much more sense. So I extracted all the Nav stuff into a demo project to get it out of my app, and I still can get this to work. It looks like the panes never get added.
I put it in a repo here[^].
I would appreciate more help if you wouldn't mind.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
modified 3 days ago.
|
|
|
|
|
I was going to take a look, but it looks like your repo is private.
|
|
|
|
|
Oops. It's public now.
Thanks Pete!
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
I'll have a look in the morning.
|
|
|
|
|
Is it possible to put this path in a style? I'd like to add a data trigger to change the fill color on mouse over
<Path Grid.Column="0"
x:Name="path"
Width="16"
Height="16"
Data="M19,19H5V5H19M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M13.96,12.29L11.21,15.83L9.25,13.47L6.5,17H17.5L13.96,12.29Z"
Fill="{DynamicResource pathActiveColor}"
Stretch="Uniform"
Margin="4,2,2,2"/>
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Since there's "data", it's more a resource (to be styled) than a style.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
This did it. Thanks!
<Window.Resources>
<pre>
<Path x:Key="PathKey"
Width="20"
Height="20"
Data="M15,9H5V5H15M12,19A3,3 0 0,1 9,16A3,3 0 0,1 12,13A3,3 0 0,1 15,16A3,3 0 0,1 12,19M17,3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V7L17,3Z"
Fill="Red"
Stretch="Uniform" />
<Style TargetType="{x:Type Button}">
<Setter Property="Content">
<Setter.Value>
<DynamicResource ResourceKey='PathKey' />
</Setter.Value>
</Setter>
</Style>
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
modified 12-Apr-23 12:55pm.
|
|
|
|
|
I typically bind "Fill" or "ForeGround", etc. to an expression in the "view model" (=> ...) if it can vary from one object to the next; I use "styling" only when a group is all styled the same. (Brushes can be shared).
(UWP doesn't have XAML "data triggers" so I stopped thinking about them).
How do you reference a Path stored as a resource?
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
Ya, I'm going to. Ultimately it will be in a theme with data trigger to change the color for state, such as Enabled, Disabled, MouseOver, etc.
Thanks
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
FYI, here's what I came up with. Thanks for your help!
Control
public class MaroisPathImageButton : Button
{
#region CTOR
static MaroisPathImageButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MaroisPathImageButton), new FrameworkPropertyMetadata(typeof(MaroisPathImageButton)));
}
#endregion
#region Dependency Properties
#region DP Caption
public static readonly DependencyProperty CaptionProperty =
DependencyProperty.Register("Caption",
typeof(string),
typeof(MaroisPathImageButton),
new PropertyMetadata(""));
public string Caption
{
get { return (string)GetValue(CaptionProperty); }
set { SetValue(CaptionProperty, value); }
}
#endregion
#region DP PathData
public static readonly DependencyProperty PathDataProperty =
DependencyProperty.Register("PathData",
typeof(System.Windows.Media.Geometry),
typeof(MaroisPathImageButton),
new PropertyMetadata(null, new PropertyChangedCallback(OnPathDataChanged)));
public System.Windows.Media.Geometry PathData
{
get { return (System.Windows.Media.Geometry)GetValue(PathDataProperty); }
set { SetValue(PathDataProperty, value); }
}
private static void OnPathDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MaroisPathImageButton control = (MaroisPathImageButton)d;
}
#endregion
#endregion
}
Theme
<!--PATH DATA-->
<Geometry x:Key="toolbarHomeButtonPathData">
M12 5.69L17 10.19V18H15V12H9V18H7V10.19L12 5.69M12 3L2 12H5V20H11V14H13V20H19V12H22
</Geometry>
<!BASE PATH IMAGE BUTTON STYLE>
<Style x:Key="pathImageButtonStyle"
TargetType="{x:Type mctrls:MaroisPathImageButton}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Height" Value="40"/>
<Setter Property="Width" Value="65"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid x:Name="Grid">
<Border x:Name="border"
Margin="2"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="0"
CornerRadius="3">
<StackPanel Orientation="Vertical">
<Path x:Name="path"
Width="20"
Height="20"
Data="{Binding PathData, RelativeSource={RelativeSource TemplatedParent}}"
Fill="{StaticResource Button.Normal.Background}"
Stretch="Uniform"/>
<TextBlock Grid.Row="1"
Grid.Column="0"
x:Name="caption"
Text="{Binding Caption, RelativeSource={RelativeSource TemplatedParent}}"
Foreground="{StaticResource Button.Normal.Background}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0,0,0,2"/>
</StackPanel>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="path" Property="Fill" Value="{StaticResource Button.Normal.Foreground}" />
<Setter TargetName="caption" Property="Foreground" Value="{StaticResource Button.Hover.Foreground}" />
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource Button.Hover.Foreground}" />
<Setter TargetName="border" Property="BorderThickness" Value="1" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="path" Property="Fill" Value="{StaticResource Button.Disabled.Foreground}" />
<Setter TargetName="caption" Property="Foreground" Value="{StaticResource Button.Disabled.Foreground}" />
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource Button.Disabled.Foreground}" />
<Setter TargetName="border" Property="BorderThickness" Value="1" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!TOOLBAR HOME BUTTON STYLE>
<Style x:Key="toolbarHomeButtonStyle"
BasedOn="{StaticResource pathImageButtonStyle }"
TargetType="{x:Type mctrls:MaroisPathImageButton}">
<Setter Property="Caption" Value="Home"/>
<Setter Property="PathData" Value="{StaticResource toolbarHomeButtonPathData}"/>
</Style>
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
|
|
Something I have used in the past XAML Path Icons[^]. They allow you to download the XAML paths for icons which you can adjust as necessary.
|
|
|
|
|
OK so I got it from the MS Store on my PC. But I don't see it installed. How do I open this each time I want to use the icons?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
I normally just type XAML Path Icons in my window search bar. It opens from there for me.
|
|
|
|
|
My company has a product that runs on Windows, Android, and iOS. They want to define the app themes in json files so they can be shared across each app.
The only way I can see this working in Windows is to deserialize the json into a class and apply themes programmatically versus using theme dictionaries.
Anyone have any thoughts on this?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
modified 6-Mar-23 13:04pm.
|
|
|
|
|
I'm trying to create a Custom Control that will be a DropDown TreeView.
Basically I want to replace a comboboxe's control template with a treeview. I've tried different things, but here's what I have so far:
<Style TargetType="{x:Type local:MaroisDropDownTree}">
<pre>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Border Margin="2"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding BorderThickness}">
<TreeView ItemsSource="{Binding TreeData, RelativeSource ={RelativeSource TemplatedParent}}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
When I run it and drop it down, there's nothing there.
Can someone please point me in the right direction?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|