WPF模拟实现Gitee泡泡菜单的示例代码
wpF实现 Gitee泡泡菜单
框架使用大于等于.NET40
;
Visual Studio 2022
;
项目使用 MIT 开源许可协议;
- 需要实现泡泡菜单需要使用Canvas画布进行添加内容;
- 保证颜色随机,位置不重叠;
- 点击泡泡获得当前泡泡的值;
实现代码
1) BubblleCanvas.cs 代码如下;
usingSystem.Windows; usingSystem.Windows.Controls; usingWPFDevelopers.Helpers; usingWPFDevelopers.Utilities; namespaceWPFDevelopers.Controls { publicclassBubblleCanvas:Canvas { privatedouble_bubbleItemX; privatedouble_bubbleItemY; privateint_number; privatedouble_size; privateconstint_maxSize=120; protectedoverrideSizeArrangeOverride(SizearrangeSize) { varwidth=arrangeSize.Width; varheight=arrangeSize.Height; doubleleft=0d,top=0d; for编程(vary=0;y<(int)height/_maxSize;y++) { doubleyNum=y+1; yNum=_maxSize*yNum; for(varx=0;x<(int)width/_maxSize;x++) { if(_number>InternalChildren.Count-1) returnarrangeSize; varitem=InternalChildren[_number]asFrameworkElement; if(DoubleUtil.IsNaN(item.ActualWidth)||DoubleUtil.IsZero(item.ActualWidth)||DoubleUtil.IsNaN(item.ActualHeight)||DoubleUtil.IsZero(item.ActualHeight)) ResizeItem(item); _bubbleItemX=Canvas.GetLeft(item); _bubbleItemY=Canvas.GetTop(item); if(double.IsNaN(_bubbleItemX)||double.IsNaN(_bubbleItemY)) { doublexNum=x+1; xNum=_maxSize*xNum; _bubbleItemX=ControlsHelper.NextDouble(left,xNum-_size*ControlsHelper.NextDouble(0.6,0.9)); var_width=_bubbleItemX+_size; _width=_width>width?width-(width-_bubbleItemX)-_size:_bubbleItemX; _bubbleItemX=_width; _bubbleItemY=ControlsHelper.NextDouble(top,yNum-_size*ControlsHelper.NextDouble(0.6,0.9)); var_height=_bubbleItemY+_size; _height=_height>height?height-(height-_bubbleItemY)-_size:_bubbleItemY; _bubbleItemY=_height; } Canvas.SetLeft(item,_bubbleItemX); Canvas.SetTop(item,_bubbleItemY); left=left+_size; _number++; item.Arrange(newRect(newPoint(_bubbleItemX,_bubbleItemY),newSize(_size,_size))); } left=0d; top=top+_maxSize; } returnarrangeSize; } privatevoidResizeItem(FrameworkElementitem) { if(DoubleUtil.GreaterThanOrClose(item.DesiredSize.Width,55)) _size=ControlsHelper.GetRandom.Next(80,_maxSize); else _size=ControlsHelper.GetRandom.Next(55,_maxSize); item.Width=_size; item.Height=_size; } } }
2) ControlsHelper.cs 代码如下;
- 随机Double值;
- 随机颜色;
privatestaticlong_tick=DateTime.Now.Ticks; publicstaticRandomGetRandom=newRandom((int)(_tick&0xffffffffL)|(int)(_tick>>32)); publicstaticdoubleNextDouble(doubleminiDouble,doublemaxiDouble) { if(GetRandom!=null) { returnGetRandom.NextDouble()*(maxiDouble-miniDouble)+miniDouble; } else { return0.0d; } } publicstaticBrushRandomBrush() { varR=GetRandom.Next(255); varG=GetRandom.Next(255); varB=GetRandom.Next(255开发者_Go学习); varcolor=Color.FromRgb((byte)R,(byte)G,(byte)B); varsolidColorBrush=newSolidColorBrush(color); returnsolidColorBrush; }
3) BubbleControl.cs 代码如下;
usingSystem; usingSystem.Collections.Generic; usingSystem.Collections.ObjectModel; usingSystem.Diagnostics; usingSystem.Linq; usingSystem.Windows; usingSystem.Windows.Controls; usingSystem.Windows.Input; usingSystem.Windows.Media; usingSystem.Windows.Shapes; usingWPFDevelopers.Helpers; namespaceWPFDevelopers.Controls { [TemplatePart(Name=BorderTemplateName,Type=typeof(Border))] [TemplatePart(Name=EllipseTemplateName,Type=typeof(Ellipse))] [TemplatePart(Name=RotateTransformTemplateName,Type=typeof(RotateTransform))] publicclassBubblleControl:Control { privateconststringBorderTemplateName="PART_Border"; privateconststringEllipseTemplateName="PART_Ellipse"; privateconststringRotateTransformTemplateName="PART_EllipseRotateTransform"; privateconststringListBoxTemplateName="PART_ListBox"; privatestaticreadonlyType_typeofSelf=typeof(BubblleControl); prjavascriptivateObservableCollection<BubblleItem>_items=newObservableCollection<BubblleItem>(); privateBorder_border; privateEllipse_ellipse; privateRotateTransform_rotateTransform; privateBrush[]brushs; privateItemsControl_listBox; privatestaticRoutedCommand_clieckCommand; classBubblleItem { publicstringText{get;set;} publicBrushBg{get;set;} } staticBubblleControl() { InitializeCommands(); DefaultStyleKeyProperty.OverrideMetadata(_typeofSelf,newFrameworkPropertyMetadata(_typeofSelf)); } #regionEvent publicstaticreadonlyRoutedEventClickEvent=EventManager.RegisterRoutedEvent("Click",RoutingStrategy.Bubble,typeof(RoutedEventHandler),_typeofSelf); publiceventRoutedEventHandlerClick { add{AddHandler(ClickEvent,value);} remove{RemoveHandler(ClickEvent,value);} } #endregion #regionCommand privatestaticRoutedCommand_clickCommand=null; privatestaticvoidInitializeCommands() { _clickCommand=newRoutedCommand("Click",_typeofSelf); CommandManager.RegisterClassCommandBinding(_typeofSelf,newCommandBinding(_clickCommand,OnClickCommand,OnCanClickCommand)); } publicstaticRoutedCommandClickCommand { get{return_clickCommand;} } privatestaticvoidOnClickCommand(objectsender,ExecutedRoutedEventArgse) { varctrl=senderasBubblleControl; ctrl.SetValue(SelectedTextPropertyKey,e.Parameter?.ToString()); ctrl.RaiseEvent(newRoutedEventArgs(ClickEvent)); } privatestaticvoidOnCanClickCommand(objectsender,CanExecuteRoutedEventArgse) { e.CanExecute=true; } #endregion #regionreadonlyProperties privatestaticreadonlyDependencyPropertyKeySelectedTextPropertyKey= DependencyProperty.RegisterReadOnly("SelectedText",typeof(string),_typeofSelf,newPropertyMetadata(null)); publicstaticreadonlyDependencyPropertySelectedTextProperty=SelectedTextPropertyKey.DependencyProperty; publicstringSelectedText { get{return(string)GetValue(SelectedTextProperty);} } publicnewstaticreadonlyDependencyPropertyBorderBackgroundProperty= DependencyProperty.Register("BorderBackground",typeof(Brush),typhppeof(BubblleControl), newPropertyMetadata(null)); publicnewstaticreadonlyDependencyPropertyEarthBackgroundProperty= DependencyProperty.Register("EarthBackground",typeof(Brush),typeof(BubblleControl), newPropertyMetadata(Brushes.DarkOrchid)); publicBrushBorderBackground { get=>(Brush)this.GetValue(BorderBackgroundProperty); set=>this.SetValue(BorderBackgroundProperty,(object)value); } publicBrushEarthBackground { get=>(Brush)this.GetValue(EarthBackgroundProperty); set=>this.SetValue(EarthBackgroundProperty,(object)value); } #endregion #regionProperty publicstaticreadonlyDependencyPropertyItemsSourceProperty= DependencyProperty.Register("ItemsSource",typeof(IEnumerable<string>),typeof(BubblleControl),newPropertyMetadata(null,OnItemsSourcePropertyChanged)); publicIEnumerable<string>ItemsSource { get{return(IEnumerable<string>)GetValue(ItemsSourceProperty);} set{SetValue(ItemsSourceProperty,value);} } privatestaticvoidOnItemsSourcePropertyChanged(DependencyObjectobj,DependencyPropertyChangedEventArgse) { varctrl=objasBubblleControl; varnewValue=e.NewValueasIEnumerable<string>; if(newValue==null) { ctrl._items.Clear(); return; } foreach(variteminnewValue) { ctrl._items.Add(newBubblleItem{Text=item,Bg=ControlsHelper.RandomBrush()}); } } #endregion #regionOverride publicoverridevoidOnApplyTemplate() { base.OnApplyTemplate(); _border=GetTemplateChild(BorderTemplateName)asBorder; _ellipse=GetTemplateChild(EllipseTemplateName)asEllipse; _rotateTransform=GetTemplateChild(RotateTransformTemplateName)asRotateTransform; Loaded+=delegate { varpoint=_border.TranslatePoint(newPoint(_border.ActualWidth/2,_border.ActualHeight/2), _ellipse); _rotateTransform.CenterX=point.X-_ellipse.ActualWidth/2; _rotateTransform.CenterY=point.Y-_ellipse.ActualHeight/2; }; _listBox=GetTemplateChild(ListBoxTemplateName)asItemsControl; _listBox.ItemsSource=_items; } #endregion } }
4) BubblleControl.xaml 代码如下;
<ResourceDictionaryXMLns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:WPFDevelopers.Controls"> <ResourceDictionary.MergedDictionaries> <ResourceDictionarySource="Basic/ControlBasic.xaml"/> <ResourceDictionarySource="Basic/Animations.xaml"/> </ResourceDictionary.MergedDictionaries> <StyleTargetType="controls:BubblleControl"BasedOn="{StaticResourceControlBasicStyle}"> <SetterProperty="Width"Value="400"/> <SetterProperty="Height"Value="400"/> <SetterProperty="Background"Value="{StaticResourceWhiteSolidColorBrush}"/> <SetterProperty="BorderThickness"Value="1"/> <SetterProperty="BorderBrush"Value="{StaticResourceSecondaryTextSolidColorBrush}"/> <SetterProperty="BorderBackground"Value="{StaticResourceBaseSolidColorBrush}"/> <SetterProperty="Template"> <Setter.Value> <ControlTemplateTargetType="controls:BubblleControl"> <Gridwidth="{TemplateBindingWidth}"Height="{TemplateBindingHeight}"> <BorderBorderBrush="{TemplateBindingBorderBrush}" BorderThickness="{TemplateBindingBorderThickness}" Background="{TemplateBindingBorderBackground}" Margin="45" CornerRadius="400" x:Name="PART_Border"> <EllipseFill="{TemplateBindingBackground}"Margin="20"/> </Border> <EllipseFill="{TemplateBindingEarthBackground}" Width="26"Height="26" RenderTransformOrigin=".5,.5" x:Name="PART_Ellipse" VerticalAlignment="Top"Margin="0,35,0,0"> <Ellipse.RenderTransform> <RotateTransformx:Name="PART_EllipseRotateTransform"></RotateTransform> </Ellipse.RenderTransform> <Ellipse.Triggers> <EventTriggerRoutedEvent="Loaded"> <BeginStoryboard> <Storyboard> <DoubleAnimationStoryboard.TargetProperty="(Ellipse.RenderTransform).(RotateTransform.Angle)" RepeatBehavior="Forever" From="0"To="360" Duration="00:00:13"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger> </Ellipse.Triggers> </Ellipse> <ItemsControlx:Name="PART_ListBox" ItemsSource="{TemplateBindingItemsSource}"> <ItemsControl.ItemTemplate> <DataTemplate> <Grid> <GridWidth="{TemplateBindingWidth}" Hepythonight="{TemplateBindingHeight}"> <EllipseFill="{BindingBg}" Opacity=".4"/> <EllipseStroke="{BindingBg}" StrokeThickness=".8"/> </Grid> <TextblockVerticalAlignment="Center" HorizontalAlignment="Center" Padding="10,0"> <Hyperlink Foreground="{BindingBg}" Command="{x:Staticcontrols:BubblleControl.ClickCommand}" CommandParameter="{BindingText}" FontWeight="Normal"> <TextBlockText="{BindingText}" TextAlignment="Center" TextTrimming="CharacterEllipsis" ToolTip="{BindingText}"/> </Hyperlink> </TextBlock> </Grid> </DataTemplate> </ItemsControl.ItemTemplate> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <controls:BubblleCanvas/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
5) BubblleControlExample.xaml 代码如下;
- TabItem随机 是自动设置位置和颜色;
- TabItem自定义 可以自行定义展示的内容;
<UserControlx:Class="WPFDevelopers.Samples.ExampleViews.BubblleControlExample" 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:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers" xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews" xmlns:sys="clr-namespace:System;assembly=mscorlib" mc:Ignorable="d" d:DesignHeight="450"d:DesignWidth="800"> <Grid> <TabControl> <TabItemHeader="随机"> <wpfdev:BubblleControlx:Name="MyBubblleControl"Click="BubblleControl_Click"> <wpfdev:BubblleControl.ItemsSource> <x:ArrayType="sys:String"> <sys:String>WPF</sys:String> <sys:String>ASP.NET</sys:String> <sys:String>WinUI</sys:String> <sys:String>WebAPI</sys:String> <sys:String>Blazor</sys:String> <sys:String>MAUI</sys:String> <sys:String>Xamarin</sys:String> <sys:String>WinForm</sys:String> <sys:String>UWP</sys:String> </x:Array> </wpfdev:BubblleControl.ItemsSource> </wpfdev:BubblleControl> </TabItem> <TabItemHeader="自定义"> <wpfdev:BubblleCanvasWidth="400"Height="400"> <Grid> <GridWidth="60" Height="60"> <EllipseFill="MediumSpringGreen" Opacity=".4"/> <EllipseStroke="MediumSpringGreen" StrokeThickness=".8"/> </Grid> <TextBlockVerticalAlignment="Center" HorizontalAlignment="Center" Padding="10,0"> <Hyperlink Foreground="MediumSpringGreen" FontWeight="Normal" Command="{BindingClickCommand,RelativeSource={RelativeSourceAncestorType=local:BubblleControlExample}}"> <TextBlockText="WPF" TextAlignment="Center" TextTrimming="CharacterEllipsis"/> </Hyperlink> </TextBlock> </Grid> <Grid> <GridWidth="60" Height="60"> <EllipseFill="Brown" Opacity=".4"/> <EllipseStroke="Brown" StrokeThickness=".8"/> </Grid> <TextBlockVerticalAlignment="Center" HorizontalAlignment="Center" Padding="10,0"> <Hyperlink Foreground="Brown" FontWeight="Normal" Command="{BindingClickCommand,RelativeSource={RelativeSourceAncestorType=local:BubblleControlExample}}"> <TextBlockText="MAUI" TextAlignment="Center" TextTrimming="CharacterEllipsis"/> </Hyperlink> </TextBlock> </Grid> <Grid> <GridWidth="60" Height="60"> <EllipseFill="DeepSkyBlue" Opacity=".4"/> <EllipseStroke="DeepSkyBlue" StrokeThickness=".8"/> </Grid> <TextBlockVerticalAlignment="Center" HorizontalAlignment="Center" Padding="10,0"> <Hyperlink Foreground="DeepSkyBlue" FontWeight="Normal" Command="{BindingClickCommand,RelativeSource={RelativeSourceAncestorType=local:BubblleControlExample}}"> <TextBlockText="Blazor" TextAlignment="Center" TextTrimming="CharacterEllipsis"/> </Hyperlink> </TextBlock> </Grid> </wpfdev:BubblleCanvas> </TabItem> </TabControl> </Grid> </UserControl>
6) BubblleControlExample.xaml.cs 代码如下;
usingSystem.Windows; usingSystem.Windows.Controls; usingSystem.Windows.Input; usingWPFDevelopers.Samples.Helpers; namespaceWPFDevelopers.Samples.ExampleViews { ///<summary> ///BubbleControlExample.xaml的交互逻辑 ///</summary> publicpartialclassBubblleControlExample:UserControl { publicBubblleControlExample() { InitializeComponent(); } publicICommandClickCommand=>newRelayCommand(delegate { WPFDevelopers.Minimal.Controls.MessageBox.Show("点击完成。"); }); privatevoidBubblleControl_Click(objectsender,System.Windows.RoutedEventArgse) { MessageBox.Show($"点击了“{MyBubblleControl.SelectedText}开发者”.","提示",MessageBoxButton.OK,MessageBoxImage.Information); } } }
以上就是WPF模拟实现Gitee泡泡菜单的示例代码的详细内容,更多关于WPF泡泡菜单的资料请关注我们其它相关文章!
精彩评论