Silverlight——施工计划日报表(三)
近来非常忙,睡觉时间都不够。这一篇,尽量说完整吧,由于时间紧,可能不会详细讲解。
这一篇主要内容有:界面调整与布局、日期计划网格和内容绘制、提交事件(Silverlight调用JS函数)、进度条显示与隐藏(JS调用Silverlight函数)、左击选择时间段、右键菜单、设置完成状态、全屏等等。
如果各位有啥好建议或者代码有不当之处,请各位不要吝啬口水,尽管回复。有时间的话我会细看的。
前面说过了的,就不重复了。
最近做了一点小调整,主要是为了加入进度条。即点击提交时,进度条效果。如下所示:
Silverlight页面代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | < UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit" x:Class="PlansView.ShowPlans" xmlns:BubbleCremeTheme="System.Windows.Controls.Theming;assembly=System.Windows.Controls.Theming.BubbleCremeTheme" mc:Ignorable="d" d:DesignHeight="700" d:DesignWidth="800" Loaded="UserControl_Loaded"> < toolkit:BubbleCremeTheme > < Canvas Name="cvMain"> < Canvas Canvas.Top="3" Canvas.Left="5"> < TextBlock Canvas.Top="3" Canvas.Left="200" Height="23" Name="txtTitle" HorizontalAlignment="Center" Text="标题" FontSize="18" FontWeight="Bold" Opacity="0.7" RenderTransformOrigin="0.5,0.5" > < TextBlock.RenderTransform > < CompositeTransform /> </ TextBlock.RenderTransform > < TextBlock.Foreground > < LinearGradientBrush EndPoint="0.5,1" MappingMode="RelativeToBoundingBox" StartPoint="0.5,0"> < GradientStop Color="Black" Offset="1"/> < GradientStop Color="#FFE49C9C"/> </ LinearGradientBrush > </ TextBlock.Foreground > </ TextBlock > < StackPanel Orientation="Horizontal" Canvas.Top="27" Name="spButtons" > < Button Content="一键标记为完成" Name="btnFilishAll" Width="130" Margin="5,0,5,0" Click="btnFilishAll_Click" /> < Button Content="全屏" Name="BtnFullScreen" Width="100" Margin="5,0,5,0" Click="BtnFullScreen_Click" /> < Button Content="提交" Name="btnSubmit" Width="100" Click="Button_Click" Margin="5,0,5,0"/> </ StackPanel > </ Canvas > < ScrollViewer HorizontalContentAlignment="Left" Canvas.Top="53" Canvas.Left="2" HorizontalAlignment="Left" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Name="svPlans" MaxHeight="513"> < ScrollViewer.BorderBrush > < LinearGradientBrush EndPoint="0.5,1.5" StartPoint="0.5,0"> < GradientStop Color="#FFE0E3BC"/> < GradientStop Color="#FF6C6C5C" Offset="1"/> </ LinearGradientBrush > </ ScrollViewer.BorderBrush > < Border BorderBrush="#FF333333" BorderThickness="2" Background="#FFC1C1C1" > < Grid x:Name="gdPlans" Background="#FFC1C1C1" MouseRightButtonDown="gdPlans_MouseRightButtonDown"> </ Grid > </ Border > </ ScrollViewer > < Canvas Name="cvShowProcess" Width="600" Height="100"> < Border BorderBrush="#FF4B1313" Opacity="0.8" MinHeight="100" MinWidth="600" BorderThickness="1" Canvas.Left="84" Canvas.Top="107"> < Border.Background > < LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> < GradientStop Color="Black" Offset="0"/> < GradientStop Color="#FFC29191" Offset="1"/> </ LinearGradientBrush > </ Border.Background > < Canvas > < ProgressBar Name="pbShowStatus" MinWidth="400" Height="30" Canvas.Top="50" Canvas.Left="100" IsIndeterminate="True" /> < sdk:Label Name="lblLodingText" FontWeight="ExtraBold" FontSize="20" Canvas.Left="220" Canvas.Top="10" Content="正在处理数据..." Foreground="#FFF7EDED"/> </ Canvas > </ Border > </ Canvas > </ Canvas > </ toolkit:BubbleCremeTheme > </ UserControl > |
构造函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public ShowPlans() { try { InitializeComponent(); SetInitialValue(); #region 设置显示的时间段 if (DateType == "day" && txtTitle.Text.Length > 0) { txtTitle.Text += string .Format( "({0}~{1})" , StartDate.ToShortDateString(), StartDate.AddDays(DateColCount).ToShortDateString()); } #endregion //注册类型 HtmlPage.RegisterScriptableObject( "PlanView" , this ); } catch (Exception ex) { MessageBox.Show( "参数初始化出错:" + ex.Message, "错误" , MessageBoxButton.OK); } } |
如上所示,该构造函数主要实现了参数初始化(请参考前两篇),注册托管对象以便JS调用(这里是为了在提交完成后js隐藏Silverlight进度条以及弹出消息框),属性设置等等。
提到了JS调用Silverlight函数,顺便说说下面定义的两个函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /// <summary> /// 显示滚动条,支持js调用 /// </summary> [ScriptableMember()] public void ShowProcessStatus() { cvShowProcess.Visibility = Visibility.Visible; btnFilishAll.IsEnabled = false ; BtnFullScreen.IsEnabled = false ; btnSubmit.IsEnabled = false ; } /// <summary> /// 隐藏滚动条,支持js调用 /// </summary> [ScriptableMember()] public void HideProcessStatus( string _msg) { cvShowProcess.Visibility = Visibility.Collapsed; btnFilishAll.IsEnabled = true ; BtnFullScreen.IsEnabled = true ; btnSubmit.IsEnabled = true ; MessageBox.Show(_msg); } |
注意特性“ScriptableMember”。在构造函数中注册了对象“PlanView”后,还需要将需要调用的函数加上特性“ScriptableMember”。这样就可以了么?还不行,还需要在ASP.NET页面写点js。如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | < div id="silverlightControlHost"> < object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%"> < param name="source" value="ClientBin/PlansView.xap" /> < param name="onError" value="onSilverlightError" /> < param name="background" value="white" /> < param name="minRuntimeVersion" value="4.0.50826.0" /> < param name="onLoad" value="SilverlightLoaded" /> < param name="autoUpgrade" value="true" /> < param name="initParams" value='<%=InitParams %>' /> < a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50826.0" style="text-decoration: none"> style="border-style: none" /> </ a > </ object > < iframe id="_sl_historyFrame" style="visibility: hidden; height: 0px; width: 0px; border: 0px"></ iframe > </ div > |
注意“<param name="onLoad" value="SilverlightLoaded" /> ”,然后相应的JS如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <script type= "text/javascript" > var slCtl = null ; function SilverlightLoaded(sender) { slCtl = sender.getHost(); } function PlanViewSave(Json) { // alert(Json); setTimeout( function () { slCtl.Content.PlanView.HideProcessStatus( "操作成功!" ); }, 6000 ); } </script> |
也就是,在前台,我们可以很方便的用js调用Silverlight中的函数了。注意上面的“PlanView”,就是前面在构造函数中定义的对象。
接下来,在UserControl_Loaded事件中,对控件的位置进行了一些调整。
1 2 3 4 5 6 7 8 9 | #region 设置控件和进度条位置,并隐藏 Canvas.SetLeft(spButtons, Application.Current.Host.Content.ActualWidth - 400); Canvas.SetLeft(txtTitle, Application.Current.Host.Content.ActualWidth / 2 - 150); Canvas.SetZIndex(cvShowProcess, 999); Canvas.SetLeft(cvShowProcess, Application.Current.Host.Content.ActualWidth / 3); Canvas.SetTop(cvShowProcess, 80); cvShowProcess.Visibility = Visibility.Collapsed; svPlans.Width = Application.Current.Host.Content.ActualWidth - 8; #endregion |
值得注意的是,Application.Current.Host.Content.ActualWidth 在任何位置都能获取到宽度。而控件的Width等,在这里均无法获取到宽度和高度。
接下来介绍“SetColumnsAndRows”函数,该函数是设置列和行的。也就是生成网格。在页面上,已经放置了一个Grid的。Grid的是可以设置网格线的,不过似乎不能设置网格线的样式。因此,这里的网格线均使用的Border控件来完成。
时间紧,不能详细一一说明了,接下来的,直接贴代码好了。
具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | /// <summary> /// 设置列和行 /// </summary> /// <param name="_lstPlansData"></param> private void SetColumnsAndRows(List<PlansData> _lstPlansData) { int _recWidth = 25; int _recHeight = 21; #region 生成文本列 for ( int i = 0; i < NameColumns; i++) { ColumnDefinition _col = new ColumnDefinition() { MinWidth = 180, Width = GridLength.Auto }; gdPlans.ColumnDefinitions.Add(_col); } #endregion #region 生成日期列 //第一列放置说明文字,第二列起才是日期列 for ( int i = 0; i < DateColCount + 1; i++) { ColumnDefinition _colDay = new ColumnDefinition(); gdPlans.ColumnDefinitions.Add(_colDay); } #endregion #region 生成第一行 RowDefinition _rowHead = new RowDefinition(); gdPlans.RowDefinitions.Add(_rowHead); #endregion #region 设置表头 for ( int i = 0; i < NameColumns; i++) { TextBlock _txtPlansName = new TextBlock() { Name = "txtPlansName" + i, Text = PlanHeads[i], FontWeight = FontWeights.Bold, TextAlignment = TextAlignment.Center, Foreground = SetHeadFontColor(), }; Border _borPlansName = new Border() { BorderThickness = new Thickness(1), Background = SetHeadBackGround(), BorderBrush = SetBorderColor(), Child = _txtPlansName }; Grid.SetColumn(_borPlansName, i); Grid.SetRow(_borPlansName, RowIndex); gdPlans.Children.Add(_borPlansName); } #region 设置列头模版字符串 string _headTemp = "" ; if (DateType == "day" ) { _headTemp = "{0}" ; } else if (DateType == "week" ) { _headTemp = "{0}月{1}日~{2}月{3}日" ; _recWidth = 110; } else { _headTemp = "{0}年{1}月" ; _recWidth = 100; } #endregion #region 设置日期说明列头 TextBlock _txtExplainHead = new TextBlock() { FontWeight = FontWeights.Bold, Foreground = SetHeadFontColor(), }; Border _borExplain = new Border() { BorderBrush = SetBorderColor(), BorderThickness = new Thickness(1), Background = SetHeadBackGround(), Child = _txtExplainHead, }; Grid.SetColumn(_borExplain, NameColumns); Grid.SetRow(_borExplain, RowIndex); gdPlans.Children.Add(_borExplain); #endregion #region 设置日期列头 for ( int i = 0; i < DateColCount; i++) { TextBlock _txtDay = new TextBlock() { TextAlignment = TextAlignment.Center, FontWeight = FontWeights.Bold, Foreground = SetHeadFontColor(), }; Border _borDay = new Border() { BorderBrush = SetBorderColor(), BorderThickness = new Thickness(1), Child = _txtDay, Background = SetHeadBackGround(), }; #region 根据模版设置列头 if (DateType == "week" ) { DateTime _dtWeekStart = StartDate.AddDays(i * _weekDayCount); DateTime _dtWeekEnd = _dtWeekStart.AddDays(_weekDayCount - 1); //{0}月{1}日~{2}月{3}日 _txtDay.Text = string .Format(_headTemp, _dtWeekStart.Month, _dtWeekStart.Day, _dtWeekEnd.Month, _dtWeekEnd.Day); } else if (DateType == "day" ) { //{0} _txtDay.Text = string .Format(_headTemp, StartDate.AddDays(i).Day); } else if (DateType == "month" ) { //{0}年{1}月 DateTime _dtMonth = StartDate.AddMonths(i); _txtDay.Text = string .Format(_headTemp, _dtMonth.Year, _dtMonth.Month); } #endregion //文本列+日期说明列+日期列 Grid.SetColumn(_borDay, i + NameColumns + 1); Grid.SetRow(_borDay, 0); gdPlans.Children.Add(_borDay); } #endregion #endregion #region 设置内容行 RowIndex = 1; foreach ( var item in _lstPlansData) { int _planColCount = 0; //生成内容行 for ( int i = 0; i < item.LstPlanDate.Count; i++) { RowDefinition _row = new RowDefinition(); gdPlans.RowDefinitions.Add(_row); } //生成数据(文本头) foreach ( var _plan in item.LstPlan) { TextBlock _txtItemName = new TextBlock() { FontWeight = FontWeights.Bold, FontSize = 13, Padding = new Thickness(5, 2, 5, 0), Text = _plan.PlanName, }; Border _borItemName = new Border() { BorderBrush = SetBorderColor(), BorderThickness = new Thickness(1), Child = _txtItemName, Background = SetContentBackGround() }; Grid.SetColumn(_borItemName, _planColCount); Grid.SetRow(_borItemName, RowIndex); Grid.SetRowSpan(_borItemName, item.LstPlanDate.Count); gdPlans.Children.Add(_borItemName); _planColCount++; } //生成数据(日期) var _currentDateIndex = 0; foreach ( var _planDate in item.LstPlanDate) { bool _flagStart = false ; #region 设置日期说明列 TextBlock _txtExplain = new TextBlock() { Padding = new Thickness(5, 2, 5, 0), FontWeight = FontWeights.Bold, FontSize = 13, Name = "txtDateExplain" + RowIndex, Text = (_planDate.Explain ?? string .Empty) + (!_planDate.AllowBlank ? "*" : string .Empty), Tag = _planDate, }; Border _borItemExplain = new Border() { Name = "_borExplain" + RowIndex, BorderBrush = SetBorderColor(), BorderThickness = new Thickness(1), Child = _txtExplain, }; //设置完成状态 SetFilishState(_planDate.IsFlish, _borItemExplain); Grid.SetColumn(_borItemExplain, NameColumns); Grid.SetRow(_borItemExplain, RowIndex); gdPlans.Children.Add(_borItemExplain); #endregion for ( int i = 0; i < DateColCount; i++) { StackPanel _sp = new StackPanel() { HorizontalAlignment = HorizontalAlignment.Left, Name = "SR" + RowIndex + "C" + (i + NameColumns), }; Rectangle _rec = new Rectangle() { Name = "RR" + RowIndex + "C" + (i + NameColumns), Width = _recWidth, Height = _recHeight, Cursor = Cursors.Hand, }; SetDefaulStyle(_rec, _currentDateIndex); //设置鼠标悬浮样式 _rec.MouseMove += new MouseEventHandler(_rec_MouseMove); _rec.MouseLeave += new MouseEventHandler(_rec_MouseLeave); #region 判断时间段,并设置时间段样式 if (DateType == "day" ) { //如果是第一天,并且仅此节点 if (_planDate.StartDate != null && _planDate.StartDate.Equals(_planDate.EndDate) && i == 0 && StartDate.AddDays(i).Date.Equals(_planDate.StartDate.Value.Date)) { SetTimeSlotStyle(_rec, _currentDateIndex, true ); } else if (_planDate.StartDate != null && !_flagStart && StartDate.AddDays(i).Date.Equals(_planDate.StartDate.Value.Date)) { _flagStart = true ; } else if (_planDate.EndDate != null && _flagStart && StartDate.AddDays(i).Date.Equals(_planDate.EndDate.Value.Date)) { _flagStart = false ; SetTimeSlotStyle(_rec, _currentDateIndex, true ); } } else if (DateType == "week" ) { DateTime _dtWeekStart = StartDate.AddDays(i * _weekDayCount); if (_planDate.StartDate != null && !_flagStart) { //如果开始时间在周的时间段内,则设置为开始标签 if (_planDate.StartDate.Value.Date >= _dtWeekStart.Date && _planDate.StartDate.Value.Date <= _dtWeekStart.AddDays(_weekDayCount - 1).Date) { _flagStart = true ; } } if (_planDate.EndDate != null && _flagStart) { if (_planDate.EndDate.Value.Date < _dtWeekStart.Date) { _flagStart = false ; } } } else if (DateType == "month" ) { //如果是第一月,并且仅此节点 if (_planDate.StartDate != null && _planDate.EndDate != null && _planDate.StartDate.Value.Month.Equals(_planDate.EndDate.Value.Month) && _planDate.StartDate.Value.Year.Equals(_planDate.EndDate.Value.Year) && i == 0 && StartDate.AddMonths(i).Month.Equals(_planDate.StartDate.Value.Month) && StartDate.AddMonths(i).Year.Equals(_planDate.StartDate.Value.Year)) { SetTimeSlotStyle(_rec, _currentDateIndex, true ); } else if (_planDate.StartDate != null && !_flagStart && StartDate.AddMonths(i).Date.Month.Equals(_planDate.StartDate.Value.Date.Month) && StartDate.AddMonths(i).Date.Year.Equals(_planDate.StartDate.Value.Date.Year)) { _flagStart = true ; } else if (_planDate.EndDate != null && _flagStart && StartDate.AddMonths(i).Date.Month.Equals(_planDate.EndDate.Value.Date.Month) && StartDate.AddMonths(i).Date.Year.Equals(_planDate.EndDate.Value.Date.Year)) { _flagStart = false ; SetTimeSlotStyle(_rec, _currentDateIndex, true ); } } if (_flagStart) { SetTimeSlotStyle(_rec, _currentDateIndex, true ); } #endregion if (!_planDate.IsReadOnly && (!_planDate.IsFlish)) { _rec.MouseLeftButtonDown += new MouseButtonEventHandler(_rec_MouseLeftButtonDown); } if (!_planDate.IsFlish) { //设置右键菜单 ContextMenu SetDateContentMenu = new ContextMenu(); MenuItem _miFilish = new MenuItem() { Tag = _rec, Header = "完成" , }; _miFilish.Click += new RoutedEventHandler(_miFilish_Click); SetDateContentMenu.Items.Add(_miFilish); ContextMenuService.SetContextMenu(_rec, SetDateContentMenu); } else { if (_planDate.AllowCancel) { //设置右键菜单 ContextMenu SetDateContentMenu = new ContextMenu(); //设置右键菜单 MenuItem _miCancelFilish = new MenuItem() { Tag = _rec, Header = "撤销完成" , }; _miCancelFilish.Click += new RoutedEventHandler(_miCancelFilish_Click); SetDateContentMenu.Items.Add(_miCancelFilish); ContextMenuService.SetContextMenu(_rec, SetDateContentMenu); } } _sp.Children.Add(_rec); Border _borSP = new Border() { Name = "bR" + RowIndex + "C" + (i + NameColumns), BorderBrush = SetBorderColor(), BorderThickness = new Thickness(0.5), Child = _sp, }; //日期列列数+文本列+日期说明列 Grid.SetColumn(_borSP, i + NameColumns + 1); Grid.SetRow(_borSP, RowIndex); gdPlans.Children.Add(_borSP); } RowIndex++; _currentDateIndex++; } } #endregion } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | /// <summary> /// 设置完成状态 /// </summary> /// <param name="_currentRowIndex">当前行</param> private void SetFilishState( int _currentRowIndex, bool IsFilsh) { Border _bor = gdPlans.FindName( "_borExplain" + _currentRowIndex) as Border; if (_bor != null ) { SetFilishState(IsFilsh, _bor); } } /// <summary> /// 设置完成状态 /// </summary> /// <param name="IsFilsh"></param> /// <param name="_bor"></param> private void SetFilishState( bool IsFilsh, Border _bor) { if (IsFilsh) _bor.Background = FilishImageBrush; else _bor.Background = SetContentBackGround(); } #region 设置内容背景色 private SolidColorBrush SetContentBackGround() { return new SolidColorBrush(ReturnColorFromString( "FFd8d8d8" )); } #endregion #region 设置表头背景色 private SolidColorBrush SetHeadBackGround() { return new SolidColorBrush(ReturnColorFromString( "FF7f7f7f" )); } #endregion #region 设置表头颜色 private SolidColorBrush SetHeadFontColor() { return new SolidColorBrush(ReturnColorFromString( "FFffffff" )); } #endregion #region 设置边框颜色 private SolidColorBrush SetBorderColor() { SolidColorBrush _scb = new SolidColorBrush(ReturnColorFromString( "FF333333" )); return _scb; } #endregion #region 右键菜单(选择时间节点) void _mi_Click( object sender, RoutedEventArgs e) { MenuItem _mi = sender as MenuItem; if (_mi != null ) { _rec_MouseLeftButtonDown(_mi.Tag, null ); } } #endregion #region 右键菜单:完成 void _miFilish_Click( object sender, RoutedEventArgs e) { try { MenuItem _mi = sender as MenuItem; if (_mi != null ) { Rectangle _rec = _mi.Tag as Rectangle; if (!SetFilishStatus(_rec)) return ; } else { MessageBox.Show( "_miFilish_Click|_mi不能为NULL" ); } } catch (Exception ex) { MessageBox.Show(ex.Message, "错误" , MessageBoxButton.OK); } } /// <summary> /// 设置完成,并保存数据 /// </summary> /// <param name="_rec"></param> /// <returns></returns> private bool SetFilishStatus(Rectangle _rec) { if (_rec == null ) { MessageBox.Show( "_miFilish_Click|_rec不能为NULL" ); return false ; } else { #region 设置参数 int _currentRowIndex; int _currentColIndex; int _startColIndex; int _endColIndex; int _startDateIndex; int _endDateIndex; int _dateIndex; int _orgStartColIndex; int _orgEndColIndex; //设置参数 SetRecParameters(_rec, out _currentRowIndex, out _currentColIndex, out _startColIndex, out _endColIndex, out _startDateIndex, out _endDateIndex, out _dateIndex, out _orgStartColIndex, out _orgEndColIndex); #endregion //如果时间段不存在 if (_startColIndex == _endColIndex && _startColIndex == -1) { MessageBoxResult _result = MessageBox.Show( "您尚未选择时间段,确定要选择吗?" , "温馨提示" , MessageBoxButton.OKCancel); if (_result == MessageBoxResult.OK) { _rec_MouseLeftButtonDown(_rec, null ); return false ; } } TextBlock _txt; PlanDate _planDate; if (!GetPlanDate(_currentRowIndex, out _txt, out _planDate)) return false ; if (_planDate.IsFlish) return false ; //设置完成 _planDate.IsFlish = true ; _planDate.HasEdit = true ; _txt.Tag = _planDate; //设置完成状态 SetFilishState(_currentRowIndex, true ); for ( int i = 0; i < DateColCount; i++) { var _recCurrent = gdPlans.FindName( "RR" + _currentRowIndex + "C" + i) as Rectangle; if (_recCurrent == null ) continue ; _recCurrent.MouseLeftButtonDown -= new MouseButtonEventHandler(_rec_MouseLeftButtonDown); ////取消选择事件 //_recCurrent.MouseLeftButtonDown -= _rec_MouseLeftButtonDown; //设置右键菜单 MenuItem _miCancelFilish = new MenuItem() { Tag = _recCurrent, Header = "撤销完成" , }; _miCancelFilish.Click += new RoutedEventHandler(_miCancelFilish_Click); ContextMenu _CM = new ContextMenu(); _CM.Items.Add(_miCancelFilish); ContextMenuService.SetContextMenu(_recCurrent, _CM); } if (!HasShowSetFilishTip) { MessageBox.Show( "设置成功,请注意行首的颜色。" , "温馨提示" , MessageBoxButton.OK); HasShowSetFilishTip = true ; } } return true ; } #region 撤销完成 void _miCancelFilish_Click( object sender, RoutedEventArgs e) { try { MenuItem _mi = sender as MenuItem; if (_mi != null ) { Rectangle _rec = _mi.Tag as Rectangle; if (_rec == null ) { MessageBox.Show( "_miFilish_Click|_rec不能为NULL" ); return ; } else { #region 设置参数 int _currentRowIndex; int _currentColIndex; int _startColIndex; int _endColIndex; int _startDateIndex; int _endDateIndex; int _dateIndex; int _orgStartColIndex; int _orgEndColIndex; //设置参数 SetRecParameters(_rec, out _currentRowIndex, out _currentColIndex, out _startColIndex, out _endColIndex, out _startDateIndex, out _endDateIndex, out _dateIndex, out _orgStartColIndex, out _orgEndColIndex); #endregion TextBlock _txt; PlanDate _planDate; if (!GetPlanDate(_currentRowIndex, out _txt, out _planDate)) { return ; } if (!_planDate.IsFlish) { return ; } //设置完成 _planDate.IsFlish = false ; _planDate.HasEdit = true ; _planDate.IsReadOnly = false ; _txt.Tag = _planDate; //设置完成状态 SetFilishState(_currentRowIndex, false ); for ( int i = 0; i < DateColCount; i++) { var _recCurrent = gdPlans.FindName( "RR" + _currentRowIndex + "C" + i) as Rectangle; if (_recCurrent == null ) { continue ; } //添加 _recCurrent.MouseLeftButtonDown += new MouseButtonEventHandler(_rec_MouseLeftButtonDown); //设置右键菜单 ContextMenu SetDateContentMenu = new ContextMenu(); MenuItem _miFilish = new MenuItem() { Tag = _recCurrent, Header = "完成" , }; _miFilish.Click += new RoutedEventHandler(_miFilish_Click); SetDateContentMenu.Items.Add(_miFilish); ContextMenuService.SetContextMenu(_recCurrent, SetDateContentMenu); } } } else { MessageBox.Show( "_miFilish_Click|_mi不能为NULL" ); } } catch (Exception ex) { MessageBox.Show(ex.Message, "错误" , MessageBoxButton.OK); } } #endregion #endregion #region 单击左键选择时间节点 void _rec_MouseLeftButtonDown( object sender, MouseButtonEventArgs e) { try { #region 选择时间点 #region 设置参数 Rectangle _rec = sender as Rectangle; if (_rec == null ) { return ; } int _currentRowIndex; int _currentColIndex; int _startColIndex; int _endColIndex; int _startDateIndex; int _endDateIndex; int _dateIndex; int _orgStartColIndex; int _orgEndColIndex; //设置参数 SetRecParameters(_rec, out _currentRowIndex, out _currentColIndex, out _startColIndex, out _endColIndex, out _startDateIndex, out _endDateIndex, out _dateIndex, out _orgStartColIndex, out _orgEndColIndex); #endregion if (_startDateIndex > _endDateIndex) { MessageBox.Show( "起始时间不对!" + _startDateIndex + "_" + _endDateIndex, "错误" , MessageBoxButton.OK); return ; } TextBlock _txt; PlanDate _planDate; if (!GetPlanDate(_currentRowIndex, out _txt, out _planDate)) { return ; } if (_startDateIndex == _endDateIndex && _startDateIndex == -1) { _planDate.StartDate = _planDate.EndDate = null ; } else if (DateType == "day" ) { _planDate.StartDate = StartDate.AddDays(_startDateIndex); _planDate.EndDate = StartDate.AddDays(_endDateIndex); } else if (DateType == "week" ) { _planDate.StartDate = StartDate.AddDays(_startDateIndex * _weekDayCount); _planDate.EndDate = StartDate.AddDays(_endDateIndex * _weekDayCount); } else if (DateType == "month" ) { _planDate.StartDate = StartDate.AddMonths(_startDateIndex); _planDate.EndDate = StartDate.AddMonths(_endDateIndex); } _planDate.HasEdit = true ; #region 计划结束时间是否允许超过今天 if (!_planDate.CanGreaterThanNow && _planDate.EndDate > DateTime.Now) { MessageBox.Show( "该计划的结束时间不能超过今天!" , "错误" , MessageBoxButton.OK); return ; } #endregion #region 是否限制了该计划的最小时间 if (_planDate.MinDate != null && _planDate.StartDate != null && _planDate.StartDate < _planDate.MinDate) { MessageBox.Show( "该计划的开始时间不能小于" + _planDate.MinDate.Value.ToString( "yyyy年MM月dd日" ) + "!" , "错误" , MessageBoxButton.OK); return ; } #endregion #region 是否设置了该计划的最大时间 if (_planDate.MaxDate != null && _planDate.EndDate != null && _planDate.EndDate > _planDate.MaxDate) { MessageBox.Show( "该计划的开始时间不能大于" + _planDate.MaxDate.Value.ToString( "yyyy年MM月dd日" ) + "!" , "错误" , MessageBoxButton.OK); return ; } #endregion for ( int i = 0; i < DateColCount; i++) { var _recCurrent = gdPlans.FindName( "RR" + _currentRowIndex + "C" + (i + NameColumns)) as Rectangle; if (_recCurrent != null && _recCurrent.Tag != null && _recCurrent.Tag.ToString().Substring(0, 1) == "1" ) { if (_startColIndex == -1) _startColIndex = (i + NameColumns); _endColIndex = (i + NameColumns); } } #endregion #region 如果时间段不存在,则只设置当前节点 if (_orgStartColIndex == _orgEndColIndex && _orgStartColIndex == -1) { SetTimeSlotStyle(_rec, _dateIndex, true ); //_startDateIndex = _endDateIndex = (_currentColIndex - 1); } #endregion #region 如果当前列号小于时间段起点,则从当前节点开始染色到时间段的起点 else if (_currentColIndex < _orgStartColIndex) { for ( int i = _currentColIndex; i < _orgStartColIndex; i++) { var _recCurrent = gdPlans.FindName( "RR" + _currentRowIndex + "C" + i) as Rectangle; if (_recCurrent != null ) { SetTimeSlotStyle(_recCurrent, _dateIndex, true ); } } //_startDateIndex = _currentColIndex - 1; ; //_endDateIndex = _orgEndColIndex - 1; ; } #endregion #region 如果当前列号大于时间段的终点,则从终点起开始染色到当前节点 else if (_currentColIndex > _orgEndColIndex) { for ( int i = _orgEndColIndex; i <= _currentColIndex; i++) { var _recCurrent = gdPlans.FindName( "RR" + _currentRowIndex + "C" + i) as Rectangle; if (_recCurrent != null ) { SetTimeSlotStyle(_recCurrent, _dateIndex, true ); } } //_startDateIndex = _orgStartColIndex - 1; //_endDateIndex = _currentColIndex - 1; } #endregion #region 如果在时间段内 else { for ( int i = _orgStartColIndex; i <= _currentColIndex; i++) { var _recCurrent = gdPlans.FindName( "RR" + _currentRowIndex + "C" + i) as Rectangle; if (_recCurrent != null ) { SetDefaulStyle(_recCurrent, _dateIndex); } } //如果当前所点不是取消所有 //if (_currentColIndex != _orgEndColIndex) //{ // _startDateIndex = _currentColIndex - 1; // _endDateIndex = _orgEndColIndex - 1; //} } _txt.Tag = _planDate; //SaveChangeTime(_currentRowIndex, _startDateIndex, _endDateIndex, _txt); #endregion } catch (Exception ex) { MessageBox.Show(ex.Message, "错误" , MessageBoxButton.OK); } } #endregion |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /// <summary> /// 获取PlanDate /// </summary> /// <param name="_currentRowIndex">当前行号</param> /// <param name="_txt">该对象所在的控件</param> /// <param name="_planDate">PlanDate对象</param> private bool GetPlanDate( int _currentRowIndex, out TextBlock _txt, out PlanDate _planDate) { _txt = gdPlans.FindName( "txtDateExplain" + _currentRowIndex) as TextBlock; if (_txt == null ) { MessageBox.Show( "对象不存在,无法操作!" , "错误" , MessageBoxButton.OK); _planDate = null ; return false ; } _planDate = _txt.Tag as PlanDate; return true ; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | /// <summary> /// 根据矩形设置参数 /// </summary> /// <param name="_rec">当前_rec</param> /// <param name="_currentRowIndex">当前对象的行序号</param> /// <param name="_currentColIndex">当前对象的列序号</param> /// <param name="_startColIndex">时间段的起点列序号</param> /// <param name="_endColIndex">时间段的终点列序号</param> /// <param name="_startDateIndex">开始日期序号</param> /// <param name="_endDateIndex">结束日期序号</param> /// <param name="_dateIndex">获取当前计划日期行序号</param> /// <param name="_orgStartColIndex">原始开始列</param> /// <param name="_orgEndColIndex">原始结束列</param> private void SetRecParameters(Rectangle _rec, out int _currentRowIndex, out int _currentColIndex, out int _startColIndex, out int _endColIndex, out int _startDateIndex, out int _endDateIndex, out int _dateIndex, out int _orgStartColIndex, out int _orgEndColIndex) { //当前对象的行序号 _currentRowIndex = Convert.ToInt32(_rec.Name.Substring(2).Split( 'C' )[0]); //当前对象的列序号 _currentColIndex = Convert.ToInt32(_rec.Name.Substring(2).Split( 'C' )[1]); //时间段的起点列序号 _startColIndex = -1; //时间段的终点列序号 _endColIndex = -1; //开始日期序号 _startDateIndex = -1; //结束日期序号 _endDateIndex = -1; ///获取当前计划日期行序号 _dateIndex = Convert.ToInt32(_rec.Tag.ToString().Split( '-' )[1]); //设置时间段起始列序号 GetStartColIndexAndEndColIndex(_currentRowIndex, ref _startColIndex, ref _endColIndex); #region 如果时间段不存在,则只设置当前节点 if (_startColIndex == _endColIndex && _startColIndex == -1) { _startDateIndex = _endDateIndex = (_currentColIndex - 1); } #endregion #region 如果当前列号小于时间段起点,则从当前节点开始染色到时间段的起点 else if (_currentColIndex < _startColIndex) { _startDateIndex = _currentColIndex - 1; ; _endDateIndex = _endColIndex - 1; ; } #endregion #region 如果当前列号大于时间段的终点,则从终点起开始染色到当前节点 else if (_currentColIndex > _endColIndex) { _startDateIndex = _startColIndex - 1; _endDateIndex = _currentColIndex - 1; } #endregion #region 如果在时间段内 else { //如果当前所点不是取消所有 if (_currentColIndex != _endColIndex) { _startDateIndex = _currentColIndex - 1; _endDateIndex = _endColIndex - 1; } } _orgStartColIndex = _startColIndex; //原始开始列 _orgEndColIndex = _endColIndex; //原始结束列 #endregion } /// <summary> /// 获取时间段的起始列序号 /// </summary> /// <param name="_currentRowIndex"></param> /// <param name="_startColIndex"></param> /// <param name="_endColIndex"></param> private void GetStartColIndexAndEndColIndex( int _currentRowIndex, ref int _startColIndex, ref int _endColIndex) { #region 获取时间段的起始列序号 for ( int i = 0; i < DateColCount; i++) { var _recCurrent = gdPlans.FindName( "RR" + _currentRowIndex + "C" + (i + NameColumns)) as Rectangle; if (_recCurrent != null && _recCurrent.Tag != null && _recCurrent.Tag.ToString().Substring(0, 1) == "1" ) { if (_startColIndex == -1) _startColIndex = (i + NameColumns); _endColIndex = (i + NameColumns); } } #endregion } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | void _rec_MouseLeave( object sender, MouseEventArgs e) { Rectangle _rec = sender as Rectangle; if (_rec != null && (_rec.Tag != null && _rec.Tag.ToString().Substring(0, 1) == "0" )) { SetDefaulStyle(_rec, Convert.ToInt32(_rec.Tag.ToString().Split( '-' )[1])); } } void _rec_MouseMove( object sender, MouseEventArgs e) { Rectangle _rec = sender as Rectangle; if (_rec != null ) { //当前对象的行序号 int _currentRowIndex = Convert.ToInt32(_rec.Name.Substring(2).Split( 'C' )[0]); TextBlock _txt = gdPlans.FindName( "txtDateExplain" + _currentRowIndex) as TextBlock; PlanDate _planDate = _txt.Tag as PlanDate; //当前计划时间段行序号 int _DateIndex = Convert.ToInt32(_rec.Tag.ToString().Split( '-' )[1]); if (_planDate.IsReadOnly == false && _rec.Tag.ToString().Substring(0, 1) == "0" ) { SetTimeSlotStyle(_rec, _DateIndex, false ); } if (_planDate == null || _planDate.StartDate == null || _planDate.EndDate == null ) { return ; } //获取相差天数 TimeSpan _ts1 = new TimeSpan(_planDate.StartDate.Value.Ticks); TimeSpan _ts2 = new TimeSpan(_planDate.EndDate.Value.Ticks); int _DifferDaysCount = _ts1.Subtract(_ts2).Duration().Days + 1; //设置提示 ToolTip toolTipOnMouseOver = new ToolTip(); StackPanel _spToolTip = new StackPanel() { Orientation = Orientation.Vertical, HorizontalAlignment = HorizontalAlignment.Left }; Label _lblTitle = new Label() { Content = _planDate.Explain ?? string .Empty, FontWeight = FontWeights.Bold }; _spToolTip.Children.Add(_lblTitle); StackPanel _spDaysCount = new StackPanel() { Orientation = Orientation.Horizontal, HorizontalAlignment = HorizontalAlignment.Left }; _spToolTip.Children.Add(_spDaysCount); Image _img = new Image() { Source = new BitmapImage( new Uri( "Images/time.png" , UriKind.Relative)) }; _spDaysCount.Children.Add(_img); if (_DifferDaysCount > 0) { Label _lblDay = new Label() { Content = _DifferDaysCount + "天" }; _spDaysCount.Children.Add(_lblDay); Label _lblDate = new Label() { Content = "起止日期:" + _planDate.StartDate.Value.ToString( "yy年MM月dd日" ) + "~" + _planDate.EndDate.Value.ToString( "yy年MM月dd日" ) }; _spToolTip.Children.Add(_lblDate); } toolTipOnMouseOver.Content = _spToolTip; ToolTipService.SetToolTip(_rec, toolTipOnMouseOver); return ; } } #region 设置样式 private void SetDefaulStyle(Rectangle _rec, int _DateIndex) { _rec.Fill = new SolidColorBrush(Colors.White); _rec.Tag = "0-" + _DateIndex; } private static void SetTimeSlotStyle(Rectangle _rec, int _DateIndex, bool isInTimeSlotStyle) { if (_DateIndex < RowBackGroundLst.Count) { _rec.Fill = RowBackGroundLst[_DateIndex]; } else { _rec.Fill = RowBackGroundLst[0]; } string flag = string .Empty; if (isInTimeSlotStyle) flag = "1" ; else flag = "0" ; flag += "-" + _DateIndex; _rec.Tag = flag; } #endregion /// <summary> /// 获取颜色 /// </summary> /// <param name="color"></param> /// <returns></returns> public Color ReturnColorFromString( string color) { string alpha = color.Substring(0, 2); string red = color.Substring(2, 2); string green = color.Substring(4, 2); string blue = color.Substring(6, 2); byte alphaByte = Convert.ToByte(alpha, 16); byte redByte = Convert.ToByte(red, 16); byte greenByte = Convert.ToByte(green, 16); byte blueByte = Convert.ToByte(blue, 16); return Color.FromArgb(alphaByte, redByte, greenByte, blueByte); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | private void Button_Click( object sender, RoutedEventArgs e) { try { int _rowIndex = 1; for ( int i = 0; i < LstPlansData.Count; i++) { for ( int j = 0; j < LstPlansData[i].LstPlanDate.Count; j++) { TextBlock _txt = gdPlans.FindName( "txtDateExplain" + _rowIndex) as TextBlock; PlanDate _plan = _txt.Tag as PlanDate; if (!_plan.AllowBlank) { if (_plan.StartDate == _plan.EndDate && _plan.EndDate == null ) { MessageBox.Show( string .Format( "您还有必选项[{0}-{1}]尚未选择,请选择!(带*号的为必选项。)" , LstPlansData[i].LstPlan[0].PlanName, _plan.Explain), "警告" , MessageBoxButton.OK); return ; } if (!_plan.IsFlish) { MessageBox.Show( string .Format( "您还有必选项[{0}-{1}]尚未标记成完成,请标记!(带*号的为必标记项。)" , LstPlansData[i].LstPlan[0].PlanName, _plan.Explain), "警告" , MessageBoxButton.OK); return ; } } LstPlansData[i].LstPlanDate[j] = _plan; _rowIndex++; } } //显示进度条 ShowProcessStatus(); //MessageBox.Show(JsonConvert.SerializeObject(_plan)); ////SaveData(); HtmlPage.Window.Invoke( "PlanViewSave" , JsonConvert.SerializeObject(LstPlansData, Formatting.Indented)); } catch (Exception ex) { MessageBox.Show(ex.Message, "错误" , MessageBoxButton.OK); } } private void BtnFullScreen_Click( object sender, RoutedEventArgs e) { BtnFullScreen.Content = Application.Current.Host.Content.IsFullScreen ? "全屏" : "退出全屏" ; Application.Current.Host.Content.IsFullScreen = Application.Current.Host.Content.IsFullScreen ? false : true ; } /// <summary> /// 一键标记为完成 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnFilishAll_Click( object sender, RoutedEventArgs e) { try { int _rowIndex = 1; for ( int i = 0; i < LstPlansData.Count; i++) { for ( int j = 0; j < LstPlansData[i].LstPlanDate.Count; j++) { TextBlock _txt = gdPlans.FindName( "txtDateExplain" + _rowIndex) as TextBlock; PlanDate _plan = _txt.Tag as PlanDate; if (!_plan.AllowBlank) { if (_plan.StartDate == _plan.EndDate && _plan.EndDate == null ) { MessageBox.Show( string .Format( "您还有必选项[{0}-{1}]尚未选择,请选择!(带*号的为必选项。)" , LstPlansData[i].LstPlan[0].PlanName, _plan.Explain), "警告" , MessageBoxButton.OK); return ; } } Rectangle _rec = gdPlans.FindName( "RR" + _rowIndex + "C" + NameColumns) as Rectangle; SetFilishStatus(_rec); _rowIndex++; } } MessageBox.Show( "标记成功。您可以点击【提交】按钮来提交更改。" , "温馨提示" , MessageBoxButton.OK); } catch (Exception ex) { MessageBox.Show(ex.Message, "错误" , MessageBoxButton.OK); } } private void gdPlans_MouseRightButtonDown( object sender, MouseButtonEventArgs e) { e.Handled = true ; //屏蔽默认右键菜单 } |
出处:http://www.cnblogs.com/codelove/
沟通渠道:编程交流群<85318032> 产品交流群<897857351>
如果喜欢作者的文章,请关注【麦扣聊技术】订阅号以便第一时间获得最新内容。本文版权归作者和湖南心莱信息科技有限公司共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
静听鸟语花香,漫赏云卷云舒。

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架